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