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