xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision 5eab803f81ff61e3e81a6486d2410623a017e36d)
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 an 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   PetscBool      has;
683   PetscErrorCode ierr;
684 
685   PetscFunctionBegin;
686   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
687   PetscValidPointer(parent, 2);
688   PetscValidPointer(name, 3);
689   PetscValidPointer(value, 4);
690 
691   ierr = PetscViewerHDF5HasAttribute(viewer, parent, name, &has);CHKERRQ(ierr);
692   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
693   if (datatype == PETSC_STRING) {
694     size_t len;
695     ierr = PetscStrlen((const char *) value, &len);CHKERRQ(ierr);
696     PetscStackCallHDF5(H5Tset_size,(dtype, len+1));
697   }
698   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
699   PetscStackCallHDF5Return(dataspace,H5Screate,(H5S_SCALAR));
700   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
701   if (has) {
702     PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
703   } else {
704 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
705     PetscStackCallHDF5Return(attribute,H5Acreate2,(obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
706 #else
707     PetscStackCallHDF5Return(attribute,H5Acreate,(obj, name, dtype, dataspace, H5P_DEFAULT));
708 #endif
709   }
710   PetscStackCallHDF5(H5Awrite,(attribute, dtype, value));
711   if (datatype == PETSC_STRING) PetscStackCallHDF5(H5Tclose,(dtype));
712   PetscStackCallHDF5(H5Aclose,(attribute));
713   PetscStackCallHDF5(H5Oclose,(obj));
714   PetscStackCallHDF5(H5Sclose,(dataspace));
715   PetscFunctionReturn(0);
716 }
717 
718 /*@C
719  PetscViewerHDF5ReadAttribute - Read an attribute
720 
721   Input Parameters:
722 + viewer - The HDF5 viewer
723 . parent - The parent name
724 . name   - The attribute name
725 - datatype - The attribute type
726 
727   Output Parameter:
728 . value    - The attribute value
729 
730   Level: advanced
731 
732 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5HasAttribute()
733 @*/
734 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, void *value)
735 {
736   hid_t          h5, obj, attribute, atype, dtype;
737   PetscErrorCode ierr;
738 
739   PetscFunctionBegin;
740   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
741   PetscValidPointer(parent, 2);
742   PetscValidPointer(name, 3);
743   PetscValidPointer(value, 4);
744   ierr = PetscDataTypeToHDF5DataType(datatype, &dtype);CHKERRQ(ierr);
745   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
746   PetscStackCallHDF5Return(obj,H5Oopen,(h5, parent, H5P_DEFAULT));
747   PetscStackCallHDF5Return(attribute,H5Aopen_name,(obj, name));
748   PetscStackCallHDF5Return(atype,H5Aget_type,(attribute));
749   if (datatype == PETSC_STRING) {
750     size_t len;
751 
752     PetscStackCallHDF5Return(len,H5Tget_size,(atype));
753     PetscStackCallHDF5(H5Tclose,(atype));
754     ierr = PetscMalloc((len+1) * sizeof(char *), &value);CHKERRQ(ierr);
755   }
756   PetscStackCallHDF5(H5Aread,(attribute, dtype, value));
757   PetscStackCallHDF5(H5Aclose,(attribute));
758   PetscStackCallHDF5(H5Dclose,(obj));
759   PetscFunctionReturn(0);
760 }
761 
762 static PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, const char name[], H5O_type_t otype, PetscBool *has)
763 {
764   hid_t          h5;
765   PetscErrorCode ierr;
766 
767   PetscFunctionBegin;
768   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
769   PetscValidPointer(name, 2);
770   PetscValidPointer(has, 3);
771   *has = PETSC_FALSE;
772   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
773   if (H5Lexists(h5, name, H5P_DEFAULT)) {
774     H5O_info_t info;
775     hid_t      obj;
776 
777     PetscStackCallHDF5Return(obj,H5Oopen,(h5, name, H5P_DEFAULT));
778     PetscStackCallHDF5(H5Oget_info,(obj, &info));
779     if (otype == info.type) *has = PETSC_TRUE;
780     PetscStackCallHDF5(H5Oclose,(obj));
781   }
782   PetscFunctionReturn(0);
783 }
784 
785 /*@C
786  PetscViewerHDF5HasAttribute - Check whether an attribute exists
787 
788   Input Parameters:
789 + viewer - The HDF5 viewer
790 . parent - The parent name
791 - name   - The attribute name
792 
793   Output Parameter:
794 . has    - Flag for attribute existence
795 
796   Level: advanced
797 
798 .seealso: PetscViewerHDF5Open(), PetscViewerHDF5WriteAttribute(), PetscViewerHDF5ReadAttribute()
799 @*/
800 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
801 {
802   hid_t          h5, dataset;
803   htri_t         hhas;
804   PetscBool      exists;
805   PetscErrorCode ierr;
806 
807   PetscFunctionBegin;
808   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
809   PetscValidPointer(parent, 2);
810   PetscValidPointer(name, 3);
811   PetscValidPointer(has, 4);
812   *has = PETSC_FALSE;
813   ierr = PetscViewerHDF5GetFileId(viewer, &h5);CHKERRQ(ierr);
814   ierr = PetscViewerHDF5HasObject(viewer, parent, H5O_TYPE_DATASET, &exists);CHKERRQ(ierr);
815   if (exists) {
816 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
817     PetscStackCallHDF5Return(dataset, H5Dopen2, (h5, parent, H5P_DEFAULT));
818 #else
819     PetscStackCallHDF5Return(dataset, H5Dopen, (h5, parent));
820 #endif
821     PetscStackCallHDF5Return(hhas, H5Aexists, (dataset, name));
822     PetscStackCallHDF5(H5Dclose,(dataset));
823     *has = hhas ? PETSC_TRUE : PETSC_FALSE;
824   }
825   PetscFunctionReturn(0);
826 }
827 
828 static PetscErrorCode PetscViewerHDF5ReadInitialize_Private(PetscViewer viewer, const char name[], HDF5ReadCtx *ctx)
829 {
830   HDF5ReadCtx    h=NULL;
831   const char    *groupname=NULL;
832   char           vecgroup[PETSC_MAX_PATH_LEN];
833   PetscErrorCode ierr;
834 
835   PetscFunctionBegin;
836   ierr = PetscNew(&h);CHKERRQ(ierr);
837   ierr = PetscViewerHDF5OpenGroup(viewer, &h->file, &h->group);CHKERRQ(ierr);
838 #if (H5_VERS_MAJOR * 10000 + H5_VERS_MINOR * 100 + H5_VERS_RELEASE >= 10800)
839   PetscStackCallHDF5Return(h->dataset,H5Dopen2,(h->group, name, H5P_DEFAULT));
840 #else
841   PetscStackCallHDF5Return(h->dataset,H5Dopen,(h->group, name));
842 #endif
843   PetscStackCallHDF5Return(h->dataspace,H5Dget_space,(h->dataset));
844   ierr = PetscViewerHDF5GetTimestep(viewer, &h->timestep);CHKERRQ(ierr);
845   ierr = PetscViewerHDF5GetGroup(viewer,&groupname);CHKERRQ(ierr);
846   ierr = PetscSNPrintf(vecgroup,PETSC_MAX_PATH_LEN,"%s/%s",groupname ? groupname : "",name);CHKERRQ(ierr);
847   ierr = PetscViewerHDF5HasAttribute(viewer,vecgroup,"complex",&h->complexVal);CHKERRQ(ierr);
848   /* Create property list for collective dataset read */
849   PetscStackCallHDF5Return(h->plist,H5Pcreate,(H5P_DATASET_XFER));
850 #if defined(PETSC_HAVE_H5PSET_FAPL_MPIO)
851   PetscStackCallHDF5(H5Pset_dxpl_mpio,(h->plist, H5FD_MPIO_COLLECTIVE));
852 #endif
853   /* To write dataset independently use H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT) */
854   *ctx = h;
855   PetscFunctionReturn(0);
856 }
857 
858 static PetscErrorCode PetscViewerHDF5ReadFinalize_Private(PetscViewer viewer, HDF5ReadCtx *ctx)
859 {
860   HDF5ReadCtx    h;
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   h = *ctx;
865   PetscStackCallHDF5(H5Pclose,(h->plist));
866   if (h->group != h->file) PetscStackCallHDF5(H5Gclose,(h->group));
867   PetscStackCallHDF5(H5Sclose,(h->dataspace));
868   PetscStackCallHDF5(H5Dclose,(h->dataset));
869   ierr = PetscFree(*ctx);CHKERRQ(ierr);
870   PetscFunctionReturn(0);
871 }
872 
873 static PetscErrorCode PetscViewerHDF5ReadSizes_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout *map_)
874 {
875   int            rdim, dim;
876   hsize_t        dims[4];
877   PetscInt       bsInd, lenInd, bs, N;
878   PetscLayout    map;
879   PetscErrorCode ierr;
880 
881   PetscFunctionBegin;
882   if (!(*map_)) {
883     ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)viewer),map_);CHKERRQ(ierr);
884   }
885   map = *map_;
886   /* calculate expected number of dimensions */
887   dim = 0;
888   if (ctx->timestep >= 0) ++dim;
889   ++dim; /* length in blocks */
890   if (ctx->complexVal) ++dim;
891   /* get actual number of dimensions in dataset */
892   PetscStackCallHDF5Return(rdim,H5Sget_simple_extent_dims,(ctx->dataspace, dims, NULL));
893   /* calculate expected dimension indices */
894   lenInd = 0;
895   if (ctx->timestep >= 0) ++lenInd;
896   bsInd = lenInd + 1;
897   ctx->dim2 = PETSC_FALSE;
898   if (rdim == dim) {
899     bs = 1; /* support vectors stored as 1D array */
900   } else if (rdim == dim+1) {
901     bs = (PetscInt) dims[bsInd];
902     if (bs == 1) ctx->dim2 = PETSC_TRUE; /* vector with blocksize of 1, still stored as 2D array */
903   } else {
904     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Dimension of array in file %d not %d as expected", rdim, dim);
905   }
906   N = (PetscInt) dims[lenInd]*bs;
907 
908   /* Set Vec sizes,blocksize,and type if not already set */
909   if (map->bs < 0) {
910     ierr = PetscLayoutSetBlockSize(map, bs);CHKERRQ(ierr);
911   } 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);
912   if (map->N < 0) {
913     ierr = PetscLayoutSetSize(map, N);CHKERRQ(ierr);
914   } 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);
915   PetscFunctionReturn(0);
916 }
917 
918 static PetscErrorCode PetscViewerHDF5ReadSelectHyperslab_Private(PetscViewer viewer, HDF5ReadCtx ctx, PetscLayout map, hid_t *memspace)
919 {
920   hsize_t        count[4], offset[4];
921   int            dim;
922   PetscInt       bs, n, low;
923   PetscErrorCode ierr;
924 
925   PetscFunctionBegin;
926   /* Compute local size and ownership range */
927   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
928   ierr = PetscLayoutGetBlockSize(map, &bs);CHKERRQ(ierr);
929   ierr = PetscLayoutGetLocalSize(map, &n);CHKERRQ(ierr);
930   ierr = PetscLayoutGetRange(map, &low, NULL);CHKERRQ(ierr);
931 
932   /* Each process defines a dataset and reads it from the hyperslab in the file */
933   dim  = 0;
934   if (ctx->timestep >= 0) {
935     count[dim]  = 1;
936     offset[dim] = ctx->timestep;
937     ++dim;
938   }
939   {
940     ierr = PetscHDF5IntCast(n/bs, &count[dim]);CHKERRQ(ierr);
941     ierr = PetscHDF5IntCast(low/bs, &offset[dim]);CHKERRQ(ierr);
942     ++dim;
943   }
944   if (bs > 1 || ctx->dim2) {
945     count[dim]  = bs;
946     offset[dim] = 0;
947     ++dim;
948   }
949   if (ctx->complexVal) {
950     count[dim]  = 2;
951     offset[dim] = 0;
952     ++dim;
953   }
954   PetscStackCallHDF5Return(*memspace,H5Screate_simple,(dim, count, NULL));
955   PetscStackCallHDF5(H5Sselect_hyperslab,(ctx->dataspace, H5S_SELECT_SET, offset, NULL, count, NULL));
956   PetscFunctionReturn(0);
957 }
958 
959 static PetscErrorCode PetscViewerHDF5ReadArray_Private(PetscViewer viewer, HDF5ReadCtx h, hid_t datatype, hid_t memspace, void *arr)
960 {
961   PetscFunctionBegin;
962   PetscStackCallHDF5(H5Dread,(h->dataset, datatype, memspace, h->dataspace, h->plist, arr));
963   PetscFunctionReturn(0);
964 }
965 
966 PetscErrorCode PetscViewerHDF5Load(PetscViewer viewer, const char *name, PetscLayout map, hid_t datatype, void **newarr)
967 {
968   HDF5ReadCtx     h=NULL;
969   hid_t           memspace=0;
970   size_t          unitsize;
971   void            *arr;
972   PetscErrorCode  ierr;
973 
974   PetscFunctionBegin;
975   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
976   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
977   ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
978   ierr = PetscViewerHDF5ReadSelectHyperslab_Private(viewer, h, map, &memspace);CHKERRQ(ierr);
979 
980 #if defined(PETSC_USE_COMPLEX)
981   if (!h->complexVal) {
982     H5T_class_t clazz = H5Tget_class(datatype);
983     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.");
984   }
985 #else
986   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.");
987 #endif
988   unitsize = H5Tget_size(datatype);
989   if (h->complexVal) unitsize *= 2;
990   ierr = PetscMalloc(map->n*unitsize, &arr);CHKERRQ(ierr);
991 
992   ierr = PetscViewerHDF5ReadArray_Private(viewer, h, datatype, memspace, arr);CHKERRQ(ierr);
993   PetscStackCallHDF5(H5Sclose,(memspace));
994   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
995   *newarr = arr;
996   PetscFunctionReturn(0);
997 }
998 
999 /*@C
1000  PetscViewerHDF5ReadSizes - Read block size and global size of a vector (Vec or IS) stored in an HDF5 file.
1001 
1002   Input Parameters:
1003 + viewer - The HDF5 viewer
1004 - name   - The vector name
1005 
1006   Output Parameter:
1007 + bs     - block size
1008 - N      - global size
1009 
1010   Note:
1011   A vector is stored as an HDF5 dataspace with 1-4 dimensions in this order:
1012   1) # timesteps (optional), 2) # blocks, 3) # elements per block (optional), 4) real and imaginary part (only for complex).
1013 
1014   A vectors can be stored as a 2D dataspace even if its blocksize is 1; see PetscViewerHDF5SetBaseDimension2().
1015 
1016   Level: advanced
1017 
1018 .seealso: PetscViewerHDF5Open(), VecLoad(), ISLoad(), VecGetSize(), ISGetSize(), PetscViewerHDF5SetBaseDimension2()
1019 @*/
1020 PetscErrorCode PetscViewerHDF5ReadSizes(PetscViewer viewer, const char name[], PetscInt *bs, PetscInt *N)
1021 {
1022   HDF5ReadCtx    h=NULL;
1023   PetscLayout    map=NULL;
1024   PetscErrorCode ierr;
1025 
1026   PetscFunctionBegin;
1027   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
1028   ierr = PetscViewerHDF5ReadInitialize_Private(viewer, name, &h);CHKERRQ(ierr);
1029   ierr = PetscViewerHDF5ReadSizes_Private(viewer, h, &map);CHKERRQ(ierr);
1030   ierr = PetscViewerHDF5ReadFinalize_Private(viewer, &h);CHKERRQ(ierr);
1031   if (bs) *bs = map->bs;
1032   if (N) *N = map->N;
1033   ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1034   PetscFunctionReturn(0);
1035 }
1036 
1037 /*
1038   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1039   is attached to a communicator, in this case the attribute is a PetscViewer.
1040 */
1041 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1042 
1043 /*@C
1044   PETSC_VIEWER_HDF5_ - Creates an HDF5 PetscViewer shared by all processors in a communicator.
1045 
1046   Collective on MPI_Comm
1047 
1048   Input Parameter:
1049 . comm - the MPI communicator to share the HDF5 PetscViewer
1050 
1051   Level: intermediate
1052 
1053   Options Database Keys:
1054 . -viewer_hdf5_filename <name>
1055 
1056   Environmental variables:
1057 . PETSC_VIEWER_HDF5_FILENAME
1058 
1059   Notes:
1060   Unlike almost all other PETSc routines, PETSC_VIEWER_HDF5_ does not return
1061   an error code.  The HDF5 PetscViewer is usually used in the form
1062 $       XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1063 
1064 .seealso: PetscViewerHDF5Open(), PetscViewerCreate(), PetscViewerDestroy()
1065 @*/
1066 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1067 {
1068   PetscErrorCode ierr;
1069   PetscBool      flg;
1070   PetscViewer    viewer;
1071   char           fname[PETSC_MAX_PATH_LEN];
1072   MPI_Comm       ncomm;
1073 
1074   PetscFunctionBegin;
1075   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1076   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1077     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_HDF5_keyval,0);
1078     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1079   }
1080   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void**)&viewer,(int*)&flg);
1081   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1082   if (!flg) { /* PetscViewer not yet created */
1083     ierr = PetscOptionsGetenv(ncomm,"PETSC_VIEWER_HDF5_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
1084     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1085     if (!flg) {
1086       ierr = PetscStrcpy(fname,"output.h5");
1087       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1088     }
1089     ierr = PetscViewerHDF5Open(ncomm,fname,FILE_MODE_WRITE,&viewer);
1090     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1091     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1092     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1093     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_HDF5_keyval,(void*)viewer);
1094     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1095   }
1096   ierr = PetscCommDestroy(&ncomm);
1097   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_HDF5_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
1098   PetscFunctionReturn(viewer);
1099 }
1100