xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision fe8322adceea202af5179e23400eaf47190af617) !
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 struct _n_HDF5ReadCtx {
20   hid_t file, group, dataset, dataspace, plist;
21   PetscInt timestep;
22   PetscBool complexVal, dim2;
23 };
24 typedef struct _n_HDF5ReadCtx* HDF5ReadCtx;
25 
26 static PetscErrorCode PetscViewerSetFromOptions_HDF5(PetscOptionItems *PetscOptionsObject,PetscViewer v)
27 {
28   PetscErrorCode   ierr;
29   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)v->data;
30 
31   PetscFunctionBegin;
32   ierr = PetscOptionsHead(PetscOptionsObject,"HDF5 PetscViewer Options");CHKERRQ(ierr);
33   ierr = PetscOptionsBool("-viewer_hdf5_base_dimension2","1d Vectors get 2 dimensions in HDF5","PetscViewerHDF5SetBaseDimension2",hdf5->basedimension2,&hdf5->basedimension2,NULL);CHKERRQ(ierr);
34   ierr = PetscOptionsBool("-viewer_hdf5_sp_output","Force data to be written in single precision","PetscViewerHDF5SetSPOutput",hdf5->spoutput,&hdf5->spoutput,NULL);CHKERRQ(ierr);
35   ierr = PetscOptionsTail();CHKERRQ(ierr);
36   PetscFunctionReturn(0);
37 }
38 
39 static PetscErrorCode PetscViewerFileClose_HDF5(PetscViewer viewer)
40 {
41   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*)viewer->data;
42   PetscErrorCode   ierr;
43 
44   PetscFunctionBegin;
45   ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);
46   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
47   PetscFunctionReturn(0);
48 }
49 
50 PetscErrorCode PetscViewerDestroy_HDF5(PetscViewer viewer)
51 {
52   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
53   PetscErrorCode   ierr;
54 
55   PetscFunctionBegin;
56   ierr = PetscViewerFileClose_HDF5(viewer);CHKERRQ(ierr);
57   while (hdf5->groups) {
58     GroupList *tmp = hdf5->groups->next;
59 
60     ierr         = PetscFree(hdf5->groups->name);CHKERRQ(ierr);
61     ierr         = PetscFree(hdf5->groups);CHKERRQ(ierr);
62     hdf5->groups = tmp;
63   }
64   ierr = PetscFree(hdf5);CHKERRQ(ierr);
65   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
66   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileGetName_C",NULL);CHKERRQ(ierr);
67   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetMode_C",NULL);CHKERRQ(ierr);
68   PetscFunctionReturn(0);
69 }
70 
71 PetscErrorCode  PetscViewerFileSetMode_HDF5(PetscViewer viewer, PetscFileMode type)
72 {
73   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
74 
75   PetscFunctionBegin;
76   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
77   hdf5->btype = type;
78   PetscFunctionReturn(0);
79 }
80 
81 PetscErrorCode  PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer, PetscBool flg)
82 {
83   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
84 
85   PetscFunctionBegin;
86   hdf5->basedimension2 = flg;
87   PetscFunctionReturn(0);
88 }
89 
90 /*@
91      PetscViewerHDF5SetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
92        dimension of 2.
93 
94     Logically Collective on PetscViewer
95 
96   Input Parameters:
97 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
98 -  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
99 
100   Options Database:
101 .  -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
102 
103 
104   Notes:
105     Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
106          of one when the dimension is lower. Others think the option is crazy.
107 
108   Level: intermediate
109 
110 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
111 
112 @*/
113 PetscErrorCode PetscViewerHDF5SetBaseDimension2(PetscViewer viewer,PetscBool flg)
114 {
115   PetscErrorCode ierr;
116 
117   PetscFunctionBegin;
118   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
119   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetBaseDimension2_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
120   PetscFunctionReturn(0);
121 }
122 
123 /*@
124      PetscViewerHDF5GetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
125        dimension of 2.
126 
127     Logically Collective on PetscViewer
128 
129   Input Parameter:
130 .  viewer - the PetscViewer, must be of type HDF5
131 
132   Output Parameter:
133 .  flg - if PETSC_TRUE the vector will always have at least a dimension of 2 even if that first dimension is of size 1
134 
135   Notes:
136     Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
137          of one when the dimension is lower. Others think the option is crazy.
138 
139   Level: intermediate
140 
141 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen()
142 
143 @*/
144 PetscErrorCode PetscViewerHDF5GetBaseDimension2(PetscViewer viewer,PetscBool *flg)
145 {
146   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
147 
148   PetscFunctionBegin;
149   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
150   *flg = hdf5->basedimension2;
151   PetscFunctionReturn(0);
152 }
153 
154 PetscErrorCode  PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer, PetscBool flg)
155 {
156   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
157 
158   PetscFunctionBegin;
159   hdf5->spoutput = flg;
160   PetscFunctionReturn(0);
161 }
162 
163 /*@
164      PetscViewerHDF5SetSPOutput - Data is written to disk in single precision even if PETSc is
165        compiled with double precision PetscReal.
166 
167     Logically Collective on PetscViewer
168 
169   Input Parameters:
170 +  viewer - the PetscViewer; if it is not hdf5 then this command is ignored
171 -  flg - if PETSC_TRUE the data will be written to disk with single precision
172 
173   Options Database:
174 .  -viewer_hdf5_sp_output - turns on (true) or off (false) output in single precision
175 
176 
177   Notes:
178     Setting this option does not make any difference if PETSc is compiled with single precision
179          in the first place. It does not affect reading datasets (HDF5 handle this internally).
180 
181   Level: intermediate
182 
183 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
184           PetscReal
185 
186 @*/
187 PetscErrorCode PetscViewerHDF5SetSPOutput(PetscViewer viewer,PetscBool flg)
188 {
189   PetscErrorCode ierr;
190 
191   PetscFunctionBegin;
192   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
193   ierr = PetscTryMethod(viewer,"PetscViewerHDF5SetSPOutput_C",(PetscViewer,PetscBool),(viewer,flg));CHKERRQ(ierr);
194   PetscFunctionReturn(0);
195 }
196 
197 /*@
198      PetscViewerHDF5GetSPOutput - Data is written to disk in single precision even if PETSc is
199        compiled with double precision PetscReal.
200 
201     Logically Collective on PetscViewer
202 
203   Input Parameter:
204 .  viewer - the PetscViewer, must be of type HDF5
205 
206   Output Parameter:
207 .  flg - if PETSC_TRUE the data will be written to disk with single precision
208 
209   Notes:
210     Setting this option does not make any difference if PETSc is compiled with single precision
211          in the first place. It does not affect reading datasets (HDF5 handle this internally).
212 
213   Level: intermediate
214 
215 .seealso: PetscViewerFileSetMode(), PetscViewerCreate(), PetscViewerSetType(), PetscViewerBinaryOpen(),
216           PetscReal
217 
218 @*/
219 PetscErrorCode PetscViewerHDF5GetSPOutput(PetscViewer viewer,PetscBool *flg)
220 {
221   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
222 
223   PetscFunctionBegin;
224   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
225   *flg = hdf5->spoutput;
226   PetscFunctionReturn(0);
227 }
228 
229 PetscErrorCode  PetscViewerFileSetName_HDF5(PetscViewer viewer, const char name[])
230 {
231   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
232 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
233   MPI_Info          info = MPI_INFO_NULL;
234 #endif
235   hid_t             plist_id;
236   PetscErrorCode    ierr;
237 
238   PetscFunctionBegin;
239   if (hdf5->file_id) PetscStackCallHDF5(H5Fclose,(hdf5->file_id));
240   if (hdf5->filename) {ierr = PetscFree(hdf5->filename);CHKERRQ(ierr);}
241   ierr = PetscStrallocpy(name, &hdf5->filename);CHKERRQ(ierr);
242   /* Set up file access property list with parallel I/O access */
243   PetscStackCallHDF5Return(plist_id,H5Pcreate,(H5P_FILE_ACCESS));
244 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
245   PetscStackCallHDF5(H5Pset_fapl_mpio,(plist_id, PetscObjectComm((PetscObject)viewer), info));
246 #endif
247   /* Create or open the file collectively */
248   switch (hdf5->btype) {
249   case FILE_MODE_READ:
250     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDONLY, plist_id));
251     break;
252   case FILE_MODE_APPEND:
253     PetscStackCallHDF5Return(hdf5->file_id,H5Fopen,(name, H5F_ACC_RDWR, plist_id));
254     break;
255   case FILE_MODE_WRITE:
256     PetscStackCallHDF5Return(hdf5->file_id,H5Fcreate,(name, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
257     break;
258   default:
259     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
260   }
261   if (hdf5->file_id < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB, "H5Fcreate failed for %s", name);
262   PetscStackCallHDF5(H5Pclose,(plist_id));
263   PetscFunctionReturn(0);
264 }
265 
266 static PetscErrorCode PetscViewerFileGetName_HDF5(PetscViewer viewer,const char **name)
267 {
268   PetscViewer_HDF5 *vhdf5 = (PetscViewer_HDF5*)viewer->data;
269 
270   PetscFunctionBegin;
271   *name = vhdf5->filename;
272   PetscFunctionReturn(0);
273 }
274 
275 /*MC
276    PETSCVIEWERHDF5 - A viewer that writes to an HDF5 file
277 
278 
279 .seealso:  PetscViewerHDF5Open(), PetscViewerStringSPrintf(), PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSCVIEWERSOCKET,
280            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSTRING,
281            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
282            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
283 
284   Level: beginner
285 M*/
286 
287 PETSC_EXTERN PetscErrorCode PetscViewerCreate_HDF5(PetscViewer v)
288 {
289   PetscViewer_HDF5 *hdf5;
290   PetscErrorCode   ierr;
291 
292   PetscFunctionBegin;
293   ierr = PetscNewLog(v,&hdf5);CHKERRQ(ierr);
294 
295   v->data                = (void*) hdf5;
296   v->ops->destroy        = PetscViewerDestroy_HDF5;
297   v->ops->setfromoptions = PetscViewerSetFromOptions_HDF5;
298   v->ops->flush          = 0;
299   hdf5->btype            = (PetscFileMode) -1;
300   hdf5->filename         = 0;
301   hdf5->timestep         = -1;
302   hdf5->groups           = NULL;
303 
304   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetName_C",PetscViewerFileSetName_HDF5);CHKERRQ(ierr);
305   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileGetName_C",PetscViewerFileGetName_HDF5);CHKERRQ(ierr);
306   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerFileSetMode_C",PetscViewerFileSetMode_HDF5);CHKERRQ(ierr);
307   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetBaseDimension2_C",PetscViewerHDF5SetBaseDimension2_HDF5);CHKERRQ(ierr);
308   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerHDF5SetSPOutput_C",PetscViewerHDF5SetSPOutput_HDF5);CHKERRQ(ierr);
309   PetscFunctionReturn(0);
310 }
311 
312 /*@C
313    PetscViewerHDF5Open - Opens a file for HDF5 input/output.
314 
315    Collective on MPI_Comm
316 
317    Input Parameters:
318 +  comm - MPI communicator
319 .  name - name of file
320 -  type - type of file
321 $    FILE_MODE_WRITE - create new file for binary output
322 $    FILE_MODE_READ - open existing file for binary input
323 $    FILE_MODE_APPEND - open existing file for binary output
324 
325    Output Parameter:
326 .  hdf5v - PetscViewer for HDF5 input/output to use with the specified file
327 
328   Options Database:
329 .  -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
330 .  -viewer_hdf5_sp_output - forces (if true) the viewer to write data in single precision independent on the precision of PetscReal
331 
332    Level: beginner
333 
334    Note:
335    This PetscViewer should be destroyed with PetscViewerDestroy().
336 
337    Concepts: HDF5 files
338    Concepts: PetscViewerHDF5^creating
339 
340 .seealso: PetscViewerASCIIOpen(), PetscViewerPushFormat(), PetscViewerDestroy(), PetscViewerHDF5SetBaseDimension2(),
341           PetscViewerHDF5SetSPOutput(), PetscViewerHDF5GetBaseDimension2(), VecView(), MatView(), VecLoad(),
342           MatLoad(), PetscFileMode, PetscViewer, PetscViewerSetType(), PetscViewerFileSetMode(), PetscViewerFileSetName()
343 @*/
344 PetscErrorCode  PetscViewerHDF5Open(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *hdf5v)
345 {
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   ierr = PetscViewerCreate(comm, hdf5v);CHKERRQ(ierr);
350   ierr = PetscViewerSetType(*hdf5v, PETSCVIEWERHDF5);CHKERRQ(ierr);
351   ierr = PetscViewerFileSetMode(*hdf5v, type);CHKERRQ(ierr);
352   ierr = PetscViewerFileSetName(*hdf5v, name);CHKERRQ(ierr);
353   PetscFunctionReturn(0);
354 }
355 
356 /*@C
357   PetscViewerHDF5GetFileId - Retrieve the file id, this file ID then can be used in direct HDF5 calls
358 
359   Not collective
360 
361   Input Parameter:
362 . viewer - the PetscViewer
363 
364   Output Parameter:
365 . file_id - The file id
366 
367   Level: intermediate
368 
369 .seealso: PetscViewerHDF5Open()
370 @*/
371 PetscErrorCode  PetscViewerHDF5GetFileId(PetscViewer viewer, hid_t *file_id)
372 {
373   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
377   if (file_id) *file_id = hdf5->file_id;
378   PetscFunctionReturn(0);
379 }
380 
381 /*@C
382   PetscViewerHDF5PushGroup - Set the current HDF5 group for output
383 
384   Not collective
385 
386   Input Parameters:
387 + viewer - the PetscViewer
388 - name - The group name
389 
390   Level: intermediate
391 
392 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
393 @*/
394 PetscErrorCode  PetscViewerHDF5PushGroup(PetscViewer viewer, const char *name)
395 {
396   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
397   GroupList        *groupNode;
398   PetscErrorCode   ierr;
399 
400   PetscFunctionBegin;
401   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
402   PetscValidCharPointer(name,2);
403   ierr = PetscNew(&groupNode);CHKERRQ(ierr);
404   ierr = PetscStrallocpy(name, (char**) &groupNode->name);CHKERRQ(ierr);
405 
406   groupNode->next = hdf5->groups;
407   hdf5->groups    = groupNode;
408   PetscFunctionReturn(0);
409 }
410 
411 /*@
412   PetscViewerHDF5PopGroup - Return the current HDF5 group for output to the previous value
413 
414   Not collective
415 
416   Input Parameter:
417 . viewer - the PetscViewer
418 
419   Level: intermediate
420 
421 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5GetGroup(),PetscViewerHDF5OpenGroup()
422 @*/
423 PetscErrorCode  PetscViewerHDF5PopGroup(PetscViewer viewer)
424 {
425   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
426   GroupList        *groupNode;
427   PetscErrorCode   ierr;
428 
429   PetscFunctionBegin;
430   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
431   if (!hdf5->groups) SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "HDF5 group stack is empty, cannot pop");
432   groupNode    = hdf5->groups;
433   hdf5->groups = hdf5->groups->next;
434   ierr         = PetscFree(groupNode->name);CHKERRQ(ierr);
435   ierr         = PetscFree(groupNode);CHKERRQ(ierr);
436   PetscFunctionReturn(0);
437 }
438 
439 /*@C
440   PetscViewerHDF5GetGroup - Get the current HDF5 group name (full path), set with PetscViewerHDF5PushGroup()/PetscViewerHDF5PopGroup().
441   If none has been assigned, returns NULL.
442 
443   Not collective
444 
445   Input Parameter:
446 . viewer - the PetscViewer
447 
448   Output Parameter:
449 . name - The group name
450 
451   Level: intermediate
452 
453 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5OpenGroup()
454 @*/
455 PetscErrorCode  PetscViewerHDF5GetGroup(PetscViewer viewer, const char **name)
456 {
457   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *) viewer->data;
458 
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
461   PetscValidPointer(name,2);
462   if (hdf5->groups) *name = hdf5->groups->name;
463   else *name = NULL;
464   PetscFunctionReturn(0);
465 }
466 
467 /*@
468   PetscViewerHDF5OpenGroup - Open the HDF5 group with the name (full path) returned by PetscViewerHDF5GetGroup(),
469   and return this group's ID and file ID.
470   If PetscViewerHDF5GetGroup() yields NULL, then group ID is file ID.
471 
472   Not collective
473 
474   Input Parameter:
475 . viewer - the PetscViewer
476 
477   Output Parameter:
478 + fileId - The HDF5 file ID
479 - groupId - The HDF5 group ID
480 
481   Level: intermediate
482 
483 .seealso: PetscViewerHDF5Open(),PetscViewerHDF5PushGroup(),PetscViewerHDF5PopGroup(),PetscViewerHDF5GetGroup()
484 @*/
485 PetscErrorCode PetscViewerHDF5OpenGroup(PetscViewer viewer, hid_t *fileId, hid_t *groupId)
486 {
487   hid_t          file_id, group;
488   htri_t         found;
489   const char     *groupName = NULL;
490   PetscErrorCode ierr;
491 
492   PetscFunctionBegin;
493   ierr = PetscViewerHDF5GetFileId(viewer, &file_id);CHKERRQ(ierr);
494   ierr = PetscViewerHDF5GetGroup(viewer, &groupName);CHKERRQ(ierr);
495   /* Open group */
496   if (groupName) {
497     PetscBool root;
498 
499     ierr = PetscStrcmp(groupName, "/", &root);CHKERRQ(ierr);
500     PetscStackCall("H5Lexists",found = H5Lexists(file_id, groupName, H5P_DEFAULT));
501     if (!root && (found <= 0)) {
502 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
503       PetscStackCallHDF5Return(group,H5Gcreate2,(file_id, groupName, 0, H5P_DEFAULT, H5P_DEFAULT));
504 #else /* deprecated HDF5 1.6 API */
505       PetscStackCallHDF5Return(group,H5Gcreate,(file_id, groupName, 0));
506 #endif
507       PetscStackCallHDF5(H5Gclose,(group));
508     }
509 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
510     PetscStackCallHDF5Return(group,H5Gopen2,(file_id, groupName, H5P_DEFAULT));
511 #else
512     PetscStackCallHDF5Return(group,H5Gopen,(file_id, groupName));
513 #endif
514   } else group = file_id;
515 
516   *fileId  = file_id;
517   *groupId = group;
518   PetscFunctionReturn(0);
519 }
520 
521 /*@
522   PetscViewerHDF5IncrementTimestep - Increments the current timestep for the HDF5 output. Fields are stacked in time.
523 
524   Not collective
525 
526   Input Parameter:
527 . viewer - the PetscViewer
528 
529   Level: intermediate
530 
531 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5SetTimestep(), PetscViewerHDF5GetTimestep()
532 @*/
533 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
534 {
535   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
536 
537   PetscFunctionBegin;
538   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
539   ++hdf5->timestep;
540   PetscFunctionReturn(0);
541 }
542 
543 /*@
544   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time. A timestep
545   of -1 disables blocking with timesteps.
546 
547   Not collective
548 
549   Input Parameters:
550 + viewer - the PetscViewer
551 - timestep - The timestep number
552 
553   Level: intermediate
554 
555 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5GetTimestep()
556 @*/
557 PetscErrorCode  PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
558 {
559   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
560 
561   PetscFunctionBegin;
562   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
563   hdf5->timestep = timestep;
564   PetscFunctionReturn(0);
565 }
566 
567 /*@
568   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
569 
570   Not collective
571 
572   Input Parameter:
573 . viewer - the PetscViewer
574 
575   Output Parameter:
576 . timestep - The timestep number
577 
578   Level: intermediate
579 
580 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5IncrementTimestep(), PetscViewerHDF5SetTimestep()
581 @*/
582 PetscErrorCode  PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
583 {
584   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
585 
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
588   PetscValidPointer(timestep,2);
589   *timestep = hdf5->timestep;
590   PetscFunctionReturn(0);
591 }
592 
593 /*@C
594   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
595 
596   Not collective
597 
598   Input Parameter:
599 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
600 
601   Output Parameter:
602 . mtype - the MPI datatype (for example MPI_DOUBLE, ...)
603 
604   Level: advanced
605 
606 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
607 @*/
608 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
609 {
610   PetscFunctionBegin;
611   if (ptype == PETSC_INT)
612 #if defined(PETSC_USE_64BIT_INDICES)
613                                        *htype = H5T_NATIVE_LLONG;
614 #else
615                                        *htype = H5T_NATIVE_INT;
616 #endif
617   else if (ptype == PETSC_DOUBLE)      *htype = H5T_NATIVE_DOUBLE;
618   else if (ptype == PETSC_LONG)        *htype = H5T_NATIVE_LONG;
619   else if (ptype == PETSC_SHORT)       *htype = H5T_NATIVE_SHORT;
620   else if (ptype == PETSC_ENUM)        *htype = H5T_NATIVE_DOUBLE;
621   else if (ptype == PETSC_BOOL)        *htype = H5T_NATIVE_DOUBLE;
622   else if (ptype == PETSC_FLOAT)       *htype = H5T_NATIVE_FLOAT;
623   else if (ptype == PETSC_CHAR)        *htype = H5T_NATIVE_CHAR;
624   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
625   else if (ptype == PETSC_STRING)      *htype = H5Tcopy(H5T_C_S1);
626   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
627   PetscFunctionReturn(0);
628 }
629 
630 /*@C
631   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
632 
633   Not collective
634 
635   Input Parameter:
636 . htype - the HDF5 datatype (for example H5T_NATIVE_DOUBLE, ...)
637 
638   Output Parameter:
639 . ptype - the PETSc datatype name (for example PETSC_DOUBLE)
640 
641   Level: advanced
642 
643 .seealso: PetscDataType, PetscHDF5DataTypeToPetscDataType()
644 @*/
645 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
646 {
647   PetscFunctionBegin;
648 #if defined(PETSC_USE_64BIT_INDICES)
649   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_LONG;
650   else if (htype == H5T_NATIVE_LLONG)  *ptype = PETSC_INT;
651 #else
652   if      (htype == H5T_NATIVE_INT)    *ptype = PETSC_INT;
653 #endif
654   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
655   else if (htype == H5T_NATIVE_LONG)   *ptype = PETSC_LONG;
656   else if (htype == H5T_NATIVE_SHORT)  *ptype = PETSC_SHORT;
657   else if (htype == H5T_NATIVE_FLOAT)  *ptype = PETSC_FLOAT;
658   else if (htype == H5T_NATIVE_CHAR)   *ptype = PETSC_CHAR;
659   else if (htype == H5T_NATIVE_UCHAR)  *ptype = PETSC_CHAR;
660   else if (htype == H5T_C_S1)          *ptype = PETSC_STRING;
661   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
662   PetscFunctionReturn(0);
663 }
664 
665 /*@C
666  PetscViewerHDF5WriteAttribute - Write a scalar attribute
667 
668   Input Parameters:
669 + viewer - The HDF5 viewer
670 . parent - The parent name
671 . name   - The attribute name
672 . datatype - The attribute type
673 - value    - The attribute value
674 
675   Level: advanced
676 
677 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5ReadAttribute(), PetscViewerHDF5HasAttribute()
678 @*/
679 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
680 {
681   hid_t          h5, dataspace, obj, attribute, dtype;
682   PetscErrorCode ierr;
683 
684   PetscFunctionBegin;
685   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
686   PetscValidPointer(parent, 2);
687   PetscValidPointer(name, 3);
688   PetscValidPointer(value, 4);
689   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
690   if (datatype == PETSC_STRING) {
691     size_t len;
692     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
693     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
694   }
695   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
696   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
697   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
698 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
699   PetscStackCallHDF5Return(attribute,H5Acreate2,(obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
700 #else
701   PetscStackCallHDF5Return(attribute,H5Acreate,(obj, name, dtype, dataspace, H5P_DEFAULT));
702 #endif
703   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
704   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
705   PetscStackCallHDF5(H5Aclose,(attribute));
706   PetscStackCallHDF5(H5Oclose,(obj));
707   PetscStackCallHDF5(H5Sclose,(dataspace));
708   PetscFunctionReturn(0);
709 }
710 
711 /*@C
712  PetscViewerHDF5ReadAttribute - Read a scalar attribute
713 
714   Input Parameters:
715 + viewer - The HDF5 viewer
716 . parent - The parent name
717 . name   - The attribute name
718 - datatype - The attribute type
719 
720   Output Parameter:
721 . value    - The attribute value
722 
723   Level: advanced
724 
725 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute()
726 @*/
727 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, void *value)
728 {
729   hid_t          h5, obj, attribute, atype, dtype;
730   PetscErrorCode ierr;
731 
732   PetscFunctionBegin;
733   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
734   PetscValidPointer(parent, 2);
735   PetscValidPointer(name, 3);
736   PetscValidPointer(value, 4);
737   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
738   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
739   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
740   PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
741   PetscStackCallHDF5Return(atype,H5Aget_type,(attribute));
742   if (datatype == PETSC_STRING) {
743     size_t len;
744 
745     PetscStackCallHDF5Return(len,H5Tget_size,(atype));
746     PetscStackCallHDF5(H5Tclose,(atype));
747     ierr = PetscMalloc((len+1) * sizeof(char *), &value);CHKERRQ(ierr);
748   }
749   PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
750   PetscStackCallHDF5(H5Aclose,(attribute));
751   PetscStackCallHDF5(H5Dclose,(obj));
752   PetscFunctionReturn(0);
753 }
754 
755 static PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, const char name[], H5O_type_t otype, PetscBool *has)
756 {
757   hid_t          h5;
758   PetscErrorCode ierr;
759 
760   PetscFunctionBegin;
761   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
762   PetscValidPointer(name, 2);
763   PetscValidPointer(has, 3);
764   *has = PETSC_FALSE;
765   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
766   if (H5Lexists(h5, name, H5P_DEFAULT)) {
767     H5O_info_t info;
768     hid_t      obj;
769 
770     PetscStackCallHDF5Return(obj,H5Oopen,(h5, name, H5P_DEFAULT));
771     PetscStackCallHDF5(H5Oget_info,(obj, &info));
772     if (otype == info.type) *has = PETSC_TRUE;
773     PetscStackCallHDF5(H5Oclose,(obj));
774   }
775   PetscFunctionReturn(0);
776 }
777 
778 /*@C
779  PetscViewerHDF5HasAttribute - Check whether a scalar attribute exists
780 
781   Input Parameters:
782 + viewer - The HDF5 viewer
783 . parent - The parent name
784 - name   - The attribute name
785 
786   Output Parameter:
787 . has    - Flag for attribute existence
788 
789   Level: advanced
790 
791 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute()
792 @*/
793 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
794 {
795   hid_t          h5, dataset;
796   htri_t         hhas;
797   PetscBool      exists;
798   PetscErrorCode ierr;
799 
800   PetscFunctionBegin;
801   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
802   PetscValidPointer(parent, 2);
803   PetscValidPointer(name, 3);
804   PetscValidPointer(has, 4);
805   *has = PETSC_FALSE;
806   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
807   ierr = PetscViewerHDF5HasObject(viewer, parent, H5O_TYPE_DATASET, &exists);CHKERRQ(ierr);
808   if (exists) {
809 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
810     PetscStackCall("H5Dopen2",dataset = H5Dopen2(h5, parent, H5P_DEFAULT));
811 #else
812     PetscStackCall("H5Dopen",dataset = H5Dopen(h5, parent));
813 #endif
814     if (dataset < 0) PetscFunctionReturn(0);
815     PetscStackCall("H5Aexists",hhas = H5Aexists(dataset, name));
816     if (hhas < 0) {
817       PetscStackCallHDF5(H5Dclose,(dataset));
818       PetscFunctionReturn(0);
819     }
820     PetscStackCallHDF5(H5Dclose,(dataset));
821     *has = hhas ? PETSC_TRUE : PETSC_FALSE;
822   }
823   PetscFunctionReturn(0);
824 }
825 
826 static PetscErrorCode PetscViewerHDF5ReadInitialize_Private(PetscViewer viewer, const char name[], HDF5ReadCtx *ctx)
827 {
828   HDF5ReadCtx    h=NULL;
829   const char    *groupname=NULL;
830   char           vecgroup[PETSC_MAX_PATH_LEN];
831   PetscErrorCode ierr;
832 
833   PetscFunctionBegin;
834   ierr = PetscNew(&h);CHKERRQ(ierr);
835   ierr = PetscViewerHDF5OpenGroup(viewer, &h->file, &h->group);CHKERRQ(ierr);
836 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
837   PetscStackCallHDF5Return(h->dataset,H5Dopen2,(h->group, name, H5P_DEFAULT));
838 #else
839   PetscStackCallHDF5Return(h->dataset,H5Dopen,(h->group, name));
840 #endif
841   PetscStackCallHDF5Return(h->dataspace,H5Dget_space,(h->dataset));
842   ierr = PetscViewerHDF5GetTimestep(viewer, &h->timestep);CHKERRQ(ierr);
843   ierr = PetscViewerHDF5GetGroup(viewer,&groupname);CHKERRQ(ierr);
844   ierr = PetscSNPrintf(vecgroup,PETSC_MAX_PATH_LEN,"%s/%s",groupname ? groupname : "",name);CHKERRQ(ierr);
845   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"complex",&h->complexVal);CHKERRQ(ierr);
846   /* Create property list for collective dataset read */
847   PetscStackCallHDF5Return(h->plist,H5Pcreate,(H5P_DATASET_XFER));
848 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
849   PetscStackCallHDF5(H5Pset_dxpl_mpio,(h->plist, H5FD_MPIO_COLLECTIVE));
850 #endif
851   /* To write dataset independently use H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT) */
852   *ctx = h;
853   PetscFunctionReturn(0);
854 }
855 
856 static PetscErrorCode PetscViewerHDF5ReadFinalize_Private(PetscViewer viewer, HDF5ReadCtx *ctx)
857 {
858   HDF5ReadCtx    h;
859   PetscErrorCode ierr;
860 
861   PetscFunctionBegin;
862   h = *ctx;
863   PetscStackCallHDF5(H5Pclose,(h->plist));
864   if (h->group != h->file) PetscStackCallHDF5(H5Gclose,(h->group));
865   PetscStackCallHDF5(H5Sclose,(h->dataspace));
866   PetscStackCallHDF5(H5Dclose,(h->dataset));
867   ierr = PetscFree(*ctx);CHKERRQ(ierr);
868   PetscFunctionReturn(0);
869 }
870 
871 static PetscErrorCode PetscViewerHDF5ReadSizes_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout *map_)
872 {
873   int            rdim, dim;
874   hsize_t        dims[4];
875   PetscInt       bsInd, lenInd, bs, N;
876   PetscLayout    map;
877   PetscErrorCode ierr;
878 
879   PetscFunctionBegin;
880   if (!(*map_)) {
881     ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)viewer),map_);CHKERRQ(ierr);
882   }
883   map = *map_;
884   /* calculate expected number of dimensions */
885   dim = 0;
886   if (ctx->timestep >= 0) ++dim;
887   ++dim; /* length in blocks */
888   if (ctx->complexVal) ++dim;
889   /* get actual number of dimensions in dataset */
890   PetscStackCallHDF5Return(rdim,H5Sget_simple_extent_dims,(ctx->dataspace, dims, NULL));
891   /* calculate expected dimension indices */
892   lenInd = 0;
893   if (ctx->timestep >= 0) ++lenInd;
894   bsInd = lenInd + 1;
895   ctx->dim2 = PETSC_FALSE;
896   if (rdim == dim) {
897     bs = 1; /* support vectors stored as 1D array */
898   } else if (rdim == dim+1) {
899     bs = (PetscInt) dims[bsInd];
900     if (bs == 1) ctx->dim2 = PETSC_TRUE; /* vector with blocksize of 1, still stored as 2D array */
901   } else {
902     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Dimension of array in file %d not %d as expected", rdim, dim);
903   }
904   N = (PetscInt) dims[lenInd]*bs;
905 
906   /* Set Vec sizes,blocksize,and type if not already set */
907   if (map->bs < 0) {
908     ierr = PetscLayoutSetBlockSize(map, bs);CHKERRQ(ierr);
909   } else if (map->bs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_UNEXPECTED, "Block size of array in file is %D, not %D as expected",bs,map->bs);
910   if (map->N < 0) {
911     ierr = PetscLayoutSetSize(map, N);CHKERRQ(ierr);
912   } else if (map->N != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_UNEXPECTED, "Global size of array in file is %D, not %D as expected",N,map->N);
913   PetscFunctionReturn(0);
914 }
915 
916 static PetscErrorCode PetscViewerHDF5ReadSelectHyperslab_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout map, hid_t *memspace)
917 {
918   hsize_t        count[4], offset[4];
919   int            dim;
920   PetscInt       bs, n, low;
921   PetscErrorCode ierr;
922 
923   PetscFunctionBegin;
924   /* Compute local size and ownership range */
925   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
926   ierr = PetscLayoutGetBlockSize(map, &bs);CHKERRQ(ierr);
927   ierr = PetscLayoutGetLocalSize(map, &n);CHKERRQ(ierr);
928   ierr = PetscLayoutGetRange(map, &low, NULL);CHKERRQ(ierr);
929 
930   /* Each process defines a dataset and reads it from the hyperslab in the file */
931   dim  = 0;
932   if (ctx->timestep >= 0) {
933     count[dim]  = 1;
934     offset[dim] = ctx->timestep;
935     ++dim;
936   }
937   {
938     ierr = PetscHDF5IntCast(n/bs, &count[dim]);CHKERRQ(ierr);
939     ierr = PetscHDF5IntCast(low/bs, &offset[dim]);CHKERRQ(ierr);
940     ++dim;
941   }
942   if (bs > 1 || ctx->dim2) {
943     count[dim]  = bs;
944     offset[dim] = 0;
945     ++dim;
946   }
947   if (ctx->complexVal) {
948     count[dim]  = 2;
949     offset[dim] = 0;
950     ++dim;
951   }
952   PetscStackCallHDF5Return(*memspace,H5Screate_simple,(dim, count, NULL));
953   PetscStackCallHDF5(H5Sselect_hyperslab,(ctx->dataspace, H5S_SELECT_SET, offset, NULL, count, NULL));
954   PetscFunctionReturn(0);
955 }
956 
957 static PetscErrorCode PetscViewerHDF5ReadArray_Private(PetscViewer viewer, HDF5ReadCtx h, hid_t datatype, hid_t memspace, void *arr)
958 {
959   PetscFunctionBegin;
960   PetscStackCallHDF5(H5Dread,(h->dataset, datatype, memspace, h->dataspace, h->plist, arr));
961   PetscFunctionReturn(0);
962 }
963 
964 PetscErrorCode PetscViewerHDF5Load(PetscViewer viewer, const char *name, PetscLayout map, hid_t datatype, void **newarr)
965 {
966   HDF5ReadCtx     h=NULL;
967   hid_t           memspace=0;
968   size_t          unitsize;
969   void            *arr;
970   PetscErrorCode  ierr;
971 
972   PetscFunctionBegin;
973   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
974   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
975   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
976   ierr = PetscViewerHDF5ReadSelectHyperslab_Private(viewer, h, map, &memspace);CHKERRQ(ierr);
977 
978 #if defined(PETSC_USE_COMPLEX)
979   if (!h->complexVal) {
980     H5T_class_t clazz = H5Tget_class(datatype);
981     if (clazz == H5T_FLOAT) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"File contains real numbers but PETSc is configured for complex. The conversion is not yet implemented. Configure with --with-scalar-type=real.");
982   }
983 #else
984   if (h->complexVal) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"File contains complex numbers but PETSc not configured for them. Configure with --with-scalar-type=complex.");
985 #endif
986   unitsize = H5Tget_size(datatype);
987   if (h->complexVal) unitsize *= 2;
988   ierr = PetscMalloc(map->n*unitsize, &arr);CHKERRQ(ierr);
989 
990   ierr = PetscViewerHDF5ReadArray_Private(viewer, h, datatype, memspace, arr);CHKERRQ(ierr);
991   PetscStackCallHDF5(H5Sclose,(memspace));
992   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
993   *newarr = arr;
994   PetscFunctionReturn(0);
995 }
996 
997 /*@C
998  PetscViewerHDF5ReadSizes - Read block size and global size of a vector (Vec or IS) stored in an HDF5 file.
999 
1000   Input Parameters:
1001 + viewer - The HDF5 viewer
1002 - name   - The vector name
1003 
1004   Output Parameter:
1005 + bs     - block size
1006 - N      - global size
1007 
1008   Note:
1009   A vector is stored as an HDF5 dataspace with 1-4 dimensions in this order:
1010   1) # timesteps (optional), 2) # blocks, 3) # elements per block (optional), 4) real and imaginary part (only for complex).
1011 
1012   A vectors can be stored as a 2D dataspace even if its blocksize is 1; see PetscViewerHDF5SetBaseDimension2().
1013 
1014   Level: advanced
1015 
1016 .seealso: PetscViewerHDF5Open(), VecLoad(), ISLoad(), VecGetSize(), ISGetSize(), PetscViewerHDF5SetBaseDimension2()
1017 @*/
1018 PetscErrorCode PetscViewerHDF5ReadSizes(PetscViewer viewer, const char name[], PetscInt *bs, PetscInt *N)
1019 {
1020   HDF5ReadCtx    h=NULL;
1021   PetscLayout    map=NULL;
1022   PetscErrorCode ierr;
1023 
1024   PetscFunctionBegin;
1025   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1026   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1027   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1028   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1029   if (bs) *bs = map->bs;
1030   if (N) *N = map->N;
1031   ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1032   PetscFunctionReturn(0);
1033 }
1034 
1035 /*
1036   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1037   is attached to a communicator, in this case the attribute is a PetscViewer.
1038 */
1039 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1040 
1041 /*@C
1042   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1043 
1044   Collective on MPI_Comm
1045 
1046   Input Parameter:
1047 . comm - the MPI communicator to share the HDF5 PetscViewer
1048 
1049   Level: intermediate
1050 
1051   Options Database Keys:
1052 . -viewer_hdf5_filename <name>
1053 
1054   Environmental variables:
1055 . PETSC_VIEWER_HDF5_FILENAME
1056 
1057   Notes:
1058   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1059   an error code.  The HDF5 PetscViewer is usually used in the form
1060 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1061 
1062 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1063 @*/
1064 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1065 {
1066   PetscErrorCode ierr;
1067   PetscBool      flg;
1068   PetscViewer    viewer;
1069   char           fname[PETSC_MAX_PATH_LEN];
1070   MPI_Comm       ncomm;
1071 
1072   PetscFunctionBegin;
1073   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1074   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1075     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,0);
1076     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1077   }
1078   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1079   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1080   if (!flg) { /* PetscViewer not yet created */
1081     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1082     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1083     if (!flg) {
1084       ierr = PetscStrcpy(fname,"output.h5");
1085       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1086     }
1087     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1088     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1089     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1090     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1091     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1092     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1093   }
1094   ierr = PetscCommDestroy(&ncomm);
1095   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1096   PetscFunctionReturn(viewer);
1097 }
1098