xref: /petsc/src/sys/classes/viewer/impls/hdf5/hdf5v.c (revision ae1ee55146a7ad071171b861759b85940c7e5c67)
1 #include <petsc/private/viewerhdf5impl.h> /*I "petscviewerhdf5.h" I*/
2 
3 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer, const char[], PetscBool, PetscBool *, H5O_type_t *);
4 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer, const char[], const char[], PetscBool *);
5 static PetscErrorCode PetscViewerHDF5GetGroup_Internal(PetscViewer, const char *[]);
6 
7 /*@C
8   PetscViewerHDF5GetGroup - Get the current HDF5 group name (full path), set with `PetscViewerHDF5PushGroup()`/`PetscViewerHDF5PopGroup()`.
9 
10   Not Collective
11 
12   Input Parameters:
13 + viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
14 - path   - (Optional) The path relative to the pushed group
15 
16   Output Parameter:
17 . abspath - The absolute HDF5 path (group)
18 
19   Level: intermediate
20 
21   Notes:
22   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
23   `NULL` or empty path means the current pushed group.
24 
25   The output abspath is newly allocated so needs to be freed.
26 
27 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5OpenGroup()`, `PetscViewerHDF5WriteGroup()`
28 @*/
PetscViewerHDF5GetGroup(PetscViewer viewer,const char path[],const char * abspath[])29 PetscErrorCode PetscViewerHDF5GetGroup(PetscViewer viewer, const char path[], const char *abspath[])
30 {
31   size_t      len;
32   PetscBool   relative = PETSC_FALSE;
33   const char *group;
34   char        buf[PETSC_MAX_PATH_LEN] = "";
35 
36   PetscFunctionBegin;
37   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
38   if (path) PetscAssertPointer(path, 2);
39   PetscAssertPointer(abspath, 3);
40   PetscCall(PetscViewerHDF5GetGroup_Internal(viewer, &group));
41   PetscCall(PetscStrlen(path, &len));
42   relative = (PetscBool)(!len || path[0] != '/');
43   if (relative) {
44     PetscCall(PetscStrncpy(buf, group, sizeof(buf)));
45     if (!group || len) PetscCall(PetscStrlcat(buf, "/", sizeof(buf)));
46     PetscCall(PetscStrlcat(buf, path, sizeof(buf)));
47     PetscCall(PetscStrallocpy(buf, (char **)abspath));
48   } else {
49     PetscCall(PetscStrallocpy(path, (char **)abspath));
50   }
51   PetscFunctionReturn(PETSC_SUCCESS);
52 }
53 
PetscViewerHDF5CheckNamedObject_Internal(PetscViewer viewer,PetscObject obj)54 static PetscErrorCode PetscViewerHDF5CheckNamedObject_Internal(PetscViewer viewer, PetscObject obj)
55 {
56   PetscBool has;
57 
58   PetscFunctionBegin;
59   PetscCall(PetscViewerHDF5HasObject(viewer, obj, &has));
60   if (!has) {
61     const char *group;
62     PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &group));
63     SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Object (dataset) \"%s\" not stored in group %s", obj->name, group);
64   }
65   PetscFunctionReturn(PETSC_SUCCESS);
66 }
67 
PetscViewerSetFromOptions_HDF5(PetscViewer v,PetscOptionItems PetscOptionsObject)68 static PetscErrorCode PetscViewerSetFromOptions_HDF5(PetscViewer v, PetscOptionItems PetscOptionsObject)
69 {
70   PetscBool         flg  = PETSC_FALSE, set;
71   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)v->data;
72 
73   PetscFunctionBegin;
74   PetscOptionsHeadBegin(PetscOptionsObject, "HDF5 PetscViewer Options");
75   PetscCall(PetscOptionsBool("-viewer_hdf5_base_dimension2", "1d Vectors get 2 dimensions in HDF5", "PetscViewerHDF5SetBaseDimension2", hdf5->basedimension2, &hdf5->basedimension2, NULL));
76   PetscCall(PetscOptionsBool("-viewer_hdf5_sp_output", "Force data to be written in single precision", "PetscViewerHDF5SetSPOutput", hdf5->spoutput, &hdf5->spoutput, NULL));
77   PetscCall(PetscOptionsBool("-viewer_hdf5_collective", "Enable collective transfer mode", "PetscViewerHDF5SetCollective", flg, &flg, &set));
78   if (set) PetscCall(PetscViewerHDF5SetCollective(v, flg));
79   flg = PETSC_FALSE;
80   PetscCall(PetscOptionsBool("-viewer_hdf5_default_timestepping", "Set default timestepping state", "PetscViewerHDF5SetDefaultTimestepping", flg, &flg, &set));
81   if (set) PetscCall(PetscViewerHDF5SetDefaultTimestepping(v, flg));
82   PetscCall(PetscOptionsBool("-viewer_hdf5_compress", "Enable compression", "PetscViewerHDF5SetCompress", hdf5->compress, &hdf5->compress, NULL));
83   PetscOptionsHeadEnd();
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
PetscViewerView_HDF5(PetscViewer v,PetscViewer viewer)87 static PetscErrorCode PetscViewerView_HDF5(PetscViewer v, PetscViewer viewer)
88 {
89   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)v->data;
90   PetscBool         flg;
91 
92   PetscFunctionBegin;
93   if (hdf5->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", hdf5->filename));
94   PetscCall(PetscViewerASCIIPrintf(viewer, "Vectors with blocksize 1 saved as 2D datasets: %s\n", PetscBools[hdf5->basedimension2]));
95   PetscCall(PetscViewerASCIIPrintf(viewer, "Enforce single precision storage: %s\n", PetscBools[hdf5->spoutput]));
96   PetscCall(PetscViewerHDF5GetCollective(v, &flg));
97   PetscCall(PetscViewerASCIIPrintf(viewer, "MPI-IO transfer mode: %s\n", flg ? "collective" : "independent"));
98   PetscCall(PetscViewerASCIIPrintf(viewer, "Default timestepping: %s\n", PetscBools[hdf5->defTimestepping]));
99   PetscCall(PetscViewerASCIIPrintf(viewer, "Compression: %s\n", PetscBools[hdf5->compress]));
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
PetscViewerFileClose_HDF5(PetscViewer viewer)103 static PetscErrorCode PetscViewerFileClose_HDF5(PetscViewer viewer)
104 {
105   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
106 
107   PetscFunctionBegin;
108   PetscCall(PetscFree(hdf5->filename));
109   if (hdf5->file_id) PetscCallHDF5(H5Fclose, (hdf5->file_id));
110   PetscFunctionReturn(PETSC_SUCCESS);
111 }
112 
PetscViewerFlush_HDF5(PetscViewer viewer)113 static PetscErrorCode PetscViewerFlush_HDF5(PetscViewer viewer)
114 {
115   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
116 
117   PetscFunctionBegin;
118   if (hdf5->file_id) PetscCallHDF5(H5Fflush, (hdf5->file_id, H5F_SCOPE_LOCAL));
119   PetscFunctionReturn(PETSC_SUCCESS);
120 }
121 
PetscViewerDestroy_HDF5(PetscViewer viewer)122 static PetscErrorCode PetscViewerDestroy_HDF5(PetscViewer viewer)
123 {
124   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
125 
126   PetscFunctionBegin;
127   PetscCallHDF5(H5Pclose, (hdf5->dxpl_id));
128   PetscCall(PetscViewerFileClose_HDF5(viewer));
129   while (hdf5->groups) {
130     PetscViewerHDF5GroupList *tmp = hdf5->groups->next;
131 
132     PetscCall(PetscFree(hdf5->groups->name));
133     PetscCall(PetscFree(hdf5->groups));
134     hdf5->groups = tmp;
135   }
136   PetscCall(PetscFree(hdf5));
137   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
138   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
139   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
140   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
141   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5SetBaseDimension2_C", NULL));
142   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5SetSPOutput_C", NULL));
143   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5SetCollective_C", NULL));
144   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5GetCollective_C", NULL));
145   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5GetDefaultTimestepping_C", NULL));
146   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5SetDefaultTimestepping_C", NULL));
147   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5SetCompress_C", NULL));
148   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerHDF5GetCompress_C", NULL));
149   PetscFunctionReturn(PETSC_SUCCESS);
150 }
151 
PetscViewerFileSetMode_HDF5(PetscViewer viewer,PetscFileMode type)152 static PetscErrorCode PetscViewerFileSetMode_HDF5(PetscViewer viewer, PetscFileMode type)
153 {
154   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
155 
156   PetscFunctionBegin;
157   hdf5->btype = type;
158   PetscFunctionReturn(PETSC_SUCCESS);
159 }
160 
PetscViewerFileGetMode_HDF5(PetscViewer viewer,PetscFileMode * type)161 static PetscErrorCode PetscViewerFileGetMode_HDF5(PetscViewer viewer, PetscFileMode *type)
162 {
163   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
164 
165   PetscFunctionBegin;
166   *type = hdf5->btype;
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer,PetscBool flg)170 static PetscErrorCode PetscViewerHDF5SetBaseDimension2_HDF5(PetscViewer viewer, PetscBool flg)
171 {
172   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
173 
174   PetscFunctionBegin;
175   hdf5->basedimension2 = flg;
176   PetscFunctionReturn(PETSC_SUCCESS);
177 }
178 
179 /*@
180   PetscViewerHDF5SetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
181   dimension of 2.
182 
183   Logically Collective
184 
185   Input Parameters:
186 + viewer - the `PetscViewer`; if it is a `PETSCVIEWERHDF5` then this command is ignored
187 - flg    - if `PETSC_TRUE` the vector will always have at least a dimension of 2 even if that first dimension is of size 1
188 
189   Options Database Key:
190 . -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
191 
192   Level: intermediate
193 
194   Note:
195   Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
196   of one when the dimension is lower. Others think the option is crazy.
197 
198 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
199 @*/
PetscViewerHDF5SetBaseDimension2(PetscViewer viewer,PetscBool flg)200 PetscErrorCode PetscViewerHDF5SetBaseDimension2(PetscViewer viewer, PetscBool flg)
201 {
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
204   PetscTryMethod(viewer, "PetscViewerHDF5SetBaseDimension2_C", (PetscViewer, PetscBool), (viewer, flg));
205   PetscFunctionReturn(PETSC_SUCCESS);
206 }
207 
208 /*@
209   PetscViewerHDF5GetBaseDimension2 - Vectors of 1 dimension (i.e. bs/dof is 1) will be saved in the HDF5 file with a
210   dimension of 2.
211 
212   Logically Collective
213 
214   Input Parameter:
215 . viewer - the `PetscViewer`, must be `PETSCVIEWERHDF5`
216 
217   Output Parameter:
218 . flg - if `PETSC_TRUE` the vector will always have at least a dimension of 2 even if that first dimension is of size 1
219 
220   Level: intermediate
221 
222   Note:
223   Setting this option allegedly makes code that reads the HDF5 in easier since they do not have a "special case" of a bs/dof
224   of one when the dimension is lower. Others think the option is crazy.
225 
226 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
227 @*/
PetscViewerHDF5GetBaseDimension2(PetscViewer viewer,PetscBool * flg)228 PetscErrorCode PetscViewerHDF5GetBaseDimension2(PetscViewer viewer, PetscBool *flg)
229 {
230   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
231 
232   PetscFunctionBegin;
233   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
234   *flg = hdf5->basedimension2;
235   PetscFunctionReturn(PETSC_SUCCESS);
236 }
237 
PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer,PetscBool flg)238 static PetscErrorCode PetscViewerHDF5SetSPOutput_HDF5(PetscViewer viewer, PetscBool flg)
239 {
240   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
241 
242   PetscFunctionBegin;
243   hdf5->spoutput = flg;
244   PetscFunctionReturn(PETSC_SUCCESS);
245 }
246 
247 /*@
248   PetscViewerHDF5SetSPOutput - Data is written to disk in single precision even if PETSc is
249   compiled with double precision `PetscReal`.
250 
251   Logically Collective
252 
253   Input Parameters:
254 + viewer - the PetscViewer; if it is a `PETSCVIEWERHDF5` then this command is ignored
255 - flg    - if `PETSC_TRUE` the data will be written to disk with single precision
256 
257   Options Database Key:
258 . -viewer_hdf5_sp_output - turns on (true) or off (false) output in single precision
259 
260   Level: intermediate
261 
262   Note:
263   Setting this option does not make any difference if PETSc is compiled with single precision
264   in the first place. It does not affect reading datasets (HDF5 handle this internally).
265 
266 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`,
267           `PetscReal`, `PetscViewerHDF5GetSPOutput()`
268 @*/
PetscViewerHDF5SetSPOutput(PetscViewer viewer,PetscBool flg)269 PetscErrorCode PetscViewerHDF5SetSPOutput(PetscViewer viewer, PetscBool flg)
270 {
271   PetscFunctionBegin;
272   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
273   PetscTryMethod(viewer, "PetscViewerHDF5SetSPOutput_C", (PetscViewer, PetscBool), (viewer, flg));
274   PetscFunctionReturn(PETSC_SUCCESS);
275 }
276 
277 /*@
278   PetscViewerHDF5GetSPOutput - Data is written to disk in single precision even if PETSc is
279   compiled with double precision `PetscReal`.
280 
281   Logically Collective
282 
283   Input Parameter:
284 . viewer - the PetscViewer, must be of type `PETSCVIEWERHDF5`
285 
286   Output Parameter:
287 . flg - if `PETSC_TRUE` the data will be written to disk with single precision
288 
289   Level: intermediate
290 
291 .seealso: [](sec_viewers), `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`,
292           `PetscReal`, `PetscViewerHDF5SetSPOutput()`
293 @*/
PetscViewerHDF5GetSPOutput(PetscViewer viewer,PetscBool * flg)294 PetscErrorCode PetscViewerHDF5GetSPOutput(PetscViewer viewer, PetscBool *flg)
295 {
296   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
297 
298   PetscFunctionBegin;
299   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
300   *flg = hdf5->spoutput;
301   PetscFunctionReturn(PETSC_SUCCESS);
302 }
303 
PetscViewerHDF5SetCollective_HDF5(PetscViewer viewer,PetscBool flg)304 static PetscErrorCode PetscViewerHDF5SetCollective_HDF5(PetscViewer viewer, PetscBool flg)
305 {
306   PetscFunctionBegin;
307   /* H5FD_MPIO_COLLECTIVE is wrong in hdf5 1.10.2, and is the same as H5FD_MPIO_INDEPENDENT in earlier versions
308      - see e.g. https://gitlab.cosma.dur.ac.uk/swift/swiftsim/issues/431 */
309 #if H5_VERSION_GE(1, 10, 3) && defined(H5_HAVE_PARALLEL)
310   {
311     PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
312     PetscCallHDF5(H5Pset_dxpl_mpio, (hdf5->dxpl_id, flg ? H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT));
313   }
314 #else
315   if (flg) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)viewer), "Warning: PetscViewerHDF5SetCollective(viewer,PETSC_TRUE) is ignored for HDF5 versions prior to 1.10.3 or if built without MPI support\n"));
316 #endif
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   PetscViewerHDF5SetCollective - Use collective MPI-IO transfer mode for HDF5 reads and writes.
322 
323   Logically Collective; flg must contain common value
324 
325   Input Parameters:
326 + viewer - the `PetscViewer`; if it is not `PETSCVIEWERHDF5` then this command is ignored
327 - flg    - `PETSC_TRUE` for collective mode; `PETSC_FALSE` for independent mode (default)
328 
329   Options Database Key:
330 . -viewer_hdf5_collective - turns on (true) or off (false) collective transfers
331 
332   Level: intermediate
333 
334   Note:
335   Collective mode gives the MPI-IO layer underneath HDF5 a chance to do some additional collective optimizations and hence can perform better.
336   However, this works correctly only since HDF5 1.10.3 and if HDF5 is installed for MPI; hence, we ignore this setting for older versions.
337 
338   Developer Notes:
339   In the HDF5 layer, `PETSC_TRUE` / `PETSC_FALSE` means `H5Pset_dxpl_mpio()` is called with `H5FD_MPIO_COLLECTIVE` / `H5FD_MPIO_INDEPENDENT`, respectively.
340   This in turn means use of MPI_File_{read,write}_all /  MPI_File_{read,write} in the MPI-IO layer, respectively.
341   See HDF5 documentation and MPI-IO documentation for details.
342 
343 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5GetCollective()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerHDF5Open()`
344 @*/
PetscViewerHDF5SetCollective(PetscViewer viewer,PetscBool flg)345 PetscErrorCode PetscViewerHDF5SetCollective(PetscViewer viewer, PetscBool flg)
346 {
347   PetscFunctionBegin;
348   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
349   PetscValidLogicalCollectiveBool(viewer, flg, 2);
350   PetscTryMethod(viewer, "PetscViewerHDF5SetCollective_C", (PetscViewer, PetscBool), (viewer, flg));
351   PetscFunctionReturn(PETSC_SUCCESS);
352 }
353 
PetscViewerHDF5GetCollective_HDF5(PetscViewer viewer,PetscBool * flg)354 static PetscErrorCode PetscViewerHDF5GetCollective_HDF5(PetscViewer viewer, PetscBool *flg)
355 {
356 #if defined(H5_HAVE_PARALLEL)
357   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
358   H5FD_mpio_xfer_t  mode;
359 #endif
360 
361   PetscFunctionBegin;
362 #if !defined(H5_HAVE_PARALLEL)
363   *flg = PETSC_FALSE;
364 #else
365   PetscCallHDF5(H5Pget_dxpl_mpio, (hdf5->dxpl_id, &mode));
366   *flg = (mode == H5FD_MPIO_COLLECTIVE) ? PETSC_TRUE : PETSC_FALSE;
367 #endif
368   PetscFunctionReturn(PETSC_SUCCESS);
369 }
370 
371 /*@
372   PetscViewerHDF5GetCollective - Return flag whether collective MPI-IO transfer mode is used for HDF5 reads and writes.
373 
374   Not Collective
375 
376   Input Parameter:
377 . viewer - the `PETSCVIEWERHDF5` `PetscViewer`
378 
379   Output Parameter:
380 . flg - the flag
381 
382   Level: intermediate
383 
384   Note:
385   This setting works correctly only since HDF5 1.10.3 and if HDF5 was installed for MPI. For older versions, `PETSC_FALSE` will be always returned.
386   For more details, see `PetscViewerHDF5SetCollective()`.
387 
388 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5SetCollective()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerHDF5Open()`
389 @*/
PetscViewerHDF5GetCollective(PetscViewer viewer,PetscBool * flg)390 PetscErrorCode PetscViewerHDF5GetCollective(PetscViewer viewer, PetscBool *flg)
391 {
392   PetscFunctionBegin;
393   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
394   PetscAssertPointer(flg, 2);
395 
396   PetscUseMethod(viewer, "PetscViewerHDF5GetCollective_C", (PetscViewer, PetscBool *), (viewer, flg));
397   PetscFunctionReturn(PETSC_SUCCESS);
398 }
399 
PetscViewerFileSetName_HDF5(PetscViewer viewer,const char name[])400 static PetscErrorCode PetscViewerFileSetName_HDF5(PetscViewer viewer, const char name[])
401 {
402   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
403   hid_t             plist_id;
404 
405   PetscFunctionBegin;
406   if (hdf5->file_id) PetscCallHDF5(H5Fclose, (hdf5->file_id));
407   if (hdf5->filename) PetscCall(PetscFree(hdf5->filename));
408   PetscCall(PetscStrallocpy(name, &hdf5->filename));
409   /* Set up file access property list with parallel I/O access */
410   PetscCallHDF5Return(plist_id, H5Pcreate, (H5P_FILE_ACCESS));
411 #if defined(H5_HAVE_PARALLEL)
412   PetscCallHDF5(H5Pset_fapl_mpio, (plist_id, PetscObjectComm((PetscObject)viewer), MPI_INFO_NULL));
413 #endif
414   /* Create or open the file collectively */
415   switch (hdf5->btype) {
416   case FILE_MODE_READ:
417     if (PetscDefined(USE_DEBUG)) {
418       PetscMPIInt rank;
419       PetscBool   flg;
420 
421       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
422       if (rank == 0) {
423         PetscCall(PetscTestFile(hdf5->filename, 'r', &flg));
424         PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "File %s requested for reading does not exist", hdf5->filename);
425       }
426       PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)viewer)));
427     }
428     PetscCallHDF5Return(hdf5->file_id, H5Fopen, (name, H5F_ACC_RDONLY, plist_id));
429     break;
430   case FILE_MODE_APPEND:
431   case FILE_MODE_UPDATE: {
432     PetscBool flg;
433     PetscCall(PetscTestFile(hdf5->filename, 'r', &flg));
434     if (flg) PetscCallHDF5Return(hdf5->file_id, H5Fopen, (name, H5F_ACC_RDWR, plist_id));
435     else PetscCallHDF5Return(hdf5->file_id, H5Fcreate, (name, H5F_ACC_EXCL, H5P_DEFAULT, plist_id));
436     break;
437   }
438   case FILE_MODE_WRITE:
439     PetscCallHDF5Return(hdf5->file_id, H5Fcreate, (name, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
440     break;
441   case FILE_MODE_UNDEFINED:
442     SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
443   default:
444     SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[hdf5->btype]);
445   }
446   PetscCheck(hdf5->file_id >= 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "H5Fcreate failed for %s", name);
447   PetscCallHDF5(H5Pclose, (plist_id));
448   PetscCall(PetscViewerHDF5ResetAttachedDMPlexStorageVersion(viewer));
449   PetscFunctionReturn(PETSC_SUCCESS);
450 }
451 
PetscViewerFileGetName_HDF5(PetscViewer viewer,const char ** name)452 static PetscErrorCode PetscViewerFileGetName_HDF5(PetscViewer viewer, const char **name)
453 {
454   PetscViewer_HDF5 *vhdf5 = (PetscViewer_HDF5 *)viewer->data;
455 
456   PetscFunctionBegin;
457   *name = vhdf5->filename;
458   PetscFunctionReturn(PETSC_SUCCESS);
459 }
460 
PetscViewerSetUp_HDF5(PetscViewer viewer)461 static PetscErrorCode PetscViewerSetUp_HDF5(PetscViewer viewer)
462 {
463   /*
464   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5*) viewer->data;
465   */
466 
467   PetscFunctionBegin;
468   PetscFunctionReturn(PETSC_SUCCESS);
469 }
470 
PetscViewerHDF5SetDefaultTimestepping_HDF5(PetscViewer viewer,PetscBool flg)471 static PetscErrorCode PetscViewerHDF5SetDefaultTimestepping_HDF5(PetscViewer viewer, PetscBool flg)
472 {
473   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
474 
475   PetscFunctionBegin;
476   hdf5->defTimestepping = flg;
477   PetscFunctionReturn(PETSC_SUCCESS);
478 }
479 
PetscViewerHDF5GetDefaultTimestepping_HDF5(PetscViewer viewer,PetscBool * flg)480 static PetscErrorCode PetscViewerHDF5GetDefaultTimestepping_HDF5(PetscViewer viewer, PetscBool *flg)
481 {
482   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
483 
484   PetscFunctionBegin;
485   *flg = hdf5->defTimestepping;
486   PetscFunctionReturn(PETSC_SUCCESS);
487 }
488 
489 /*@
490   PetscViewerHDF5SetDefaultTimestepping - Set the flag for default timestepping
491 
492   Logically Collective
493 
494   Input Parameters:
495 + viewer - the `PetscViewer`; if it is not `PETSCVIEWERHDF5` then this command is ignored
496 - flg    - if `PETSC_TRUE` we will assume that timestepping is on
497 
498   Options Database Key:
499 . -viewer_hdf5_default_timestepping - turns on (true) or off (false) default timestepping
500 
501   Level: intermediate
502 
503   Note:
504   If the timestepping attribute is not found for an object, then the default timestepping is used
505 
506 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5GetDefaultTimestepping()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5GetTimestep()`
507 @*/
PetscViewerHDF5SetDefaultTimestepping(PetscViewer viewer,PetscBool flg)508 PetscErrorCode PetscViewerHDF5SetDefaultTimestepping(PetscViewer viewer, PetscBool flg)
509 {
510   PetscFunctionBegin;
511   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
512   PetscTryMethod(viewer, "PetscViewerHDF5SetDefaultTimestepping_C", (PetscViewer, PetscBool), (viewer, flg));
513   PetscFunctionReturn(PETSC_SUCCESS);
514 }
515 
516 /*@
517   PetscViewerHDF5GetDefaultTimestepping - Get the flag for default timestepping
518 
519   Not Collective
520 
521   Input Parameter:
522 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
523 
524   Output Parameter:
525 . flg - if `PETSC_TRUE` we will assume that timestepping is on
526 
527   Level: intermediate
528 
529 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5SetDefaultTimestepping()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5GetTimestep()`
530 @*/
PetscViewerHDF5GetDefaultTimestepping(PetscViewer viewer,PetscBool * flg)531 PetscErrorCode PetscViewerHDF5GetDefaultTimestepping(PetscViewer viewer, PetscBool *flg)
532 {
533   PetscFunctionBegin;
534   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
535   PetscUseMethod(viewer, "PetscViewerHDF5GetDefaultTimestepping_C", (PetscViewer, PetscBool *), (viewer, flg));
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
PetscViewerHDF5SetCompress_HDF5(PetscViewer viewer,PetscBool flg)539 static PetscErrorCode PetscViewerHDF5SetCompress_HDF5(PetscViewer viewer, PetscBool flg)
540 {
541   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
542 
543   PetscFunctionBegin;
544   hdf5->compress = flg;
545   PetscFunctionReturn(PETSC_SUCCESS);
546 }
547 
PetscViewerHDF5GetCompress_HDF5(PetscViewer viewer,PetscBool * flg)548 static PetscErrorCode PetscViewerHDF5GetCompress_HDF5(PetscViewer viewer, PetscBool *flg)
549 {
550   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
551 
552   PetscFunctionBegin;
553   *flg = hdf5->compress;
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 /*@
558   PetscViewerHDF5SetCompress - Set the flag for compression
559 
560   Logically Collective
561 
562   Input Parameters:
563 + viewer - the `PetscViewer`; if it is not `PETSCVIEWERHDF5` then this command is ignored
564 - flg    - if `PETSC_TRUE` we will turn on compression
565 
566   Options Database Key:
567 . -viewer_hdf5_compress - turns on (true) or off (false) compression
568 
569   Level: intermediate
570 
571 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5GetCompress()`
572 @*/
PetscViewerHDF5SetCompress(PetscViewer viewer,PetscBool flg)573 PetscErrorCode PetscViewerHDF5SetCompress(PetscViewer viewer, PetscBool flg)
574 {
575   PetscFunctionBegin;
576   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
577   PetscTryMethod(viewer, "PetscViewerHDF5SetCompress_C", (PetscViewer, PetscBool), (viewer, flg));
578   PetscFunctionReturn(PETSC_SUCCESS);
579 }
580 
581 /*@
582   PetscViewerHDF5GetCompress - Get the flag for compression
583 
584   Not Collective
585 
586   Input Parameter:
587 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
588 
589   Output Parameter:
590 . flg - if `PETSC_TRUE` we will turn on compression
591 
592   Level: intermediate
593 
594 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5SetCompress()`
595 @*/
PetscViewerHDF5GetCompress(PetscViewer viewer,PetscBool * flg)596 PetscErrorCode PetscViewerHDF5GetCompress(PetscViewer viewer, PetscBool *flg)
597 {
598   PetscFunctionBegin;
599   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
600   PetscUseMethod(viewer, "PetscViewerHDF5GetCompress_C", (PetscViewer, PetscBool *), (viewer, flg));
601   PetscFunctionReturn(PETSC_SUCCESS);
602 }
603 
604 /*MC
605    PETSCVIEWERHDF5 - A viewer that writes to an HDF5 file
606 
607   Level: beginner
608 
609 .seealso: [](sec_viewers), `PetscViewerHDF5Open()`, `PetscViewerStringSPrintf()`, `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSCVIEWERSOCKET`,
610           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`, `PETSCVIEWERSTRING`,
611           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
612           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
613 M*/
614 
PetscViewerCreate_HDF5(PetscViewer v)615 PETSC_EXTERN PetscErrorCode PetscViewerCreate_HDF5(PetscViewer v)
616 {
617   PetscViewer_HDF5 *hdf5;
618 
619   PetscFunctionBegin;
620 #if !defined(H5_HAVE_PARALLEL)
621   {
622     PetscMPIInt size;
623     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)v), &size));
624     PetscCheck(size <= 1, PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot use parallel HDF5 viewer since the given HDF5 does not support parallel I/O (H5_HAVE_PARALLEL is unset)");
625   }
626 #endif
627 
628   PetscCall(PetscNew(&hdf5));
629 
630   v->data                = (void *)hdf5;
631   v->ops->destroy        = PetscViewerDestroy_HDF5;
632   v->ops->setfromoptions = PetscViewerSetFromOptions_HDF5;
633   v->ops->setup          = PetscViewerSetUp_HDF5;
634   v->ops->view           = PetscViewerView_HDF5;
635   v->ops->flush          = PetscViewerFlush_HDF5;
636   hdf5->btype            = FILE_MODE_UNDEFINED;
637   hdf5->filename         = NULL;
638   hdf5->timestep         = -1;
639   hdf5->groups           = NULL;
640 
641   PetscCallHDF5Return(hdf5->dxpl_id, H5Pcreate, (H5P_DATASET_XFER));
642 
643   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", PetscViewerFileSetName_HDF5));
644   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetName_C", PetscViewerFileGetName_HDF5));
645   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_HDF5));
646   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_HDF5));
647   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5SetBaseDimension2_C", PetscViewerHDF5SetBaseDimension2_HDF5));
648   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5SetSPOutput_C", PetscViewerHDF5SetSPOutput_HDF5));
649   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5SetCollective_C", PetscViewerHDF5SetCollective_HDF5));
650   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5GetCollective_C", PetscViewerHDF5GetCollective_HDF5));
651   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5GetDefaultTimestepping_C", PetscViewerHDF5GetDefaultTimestepping_HDF5));
652   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5SetDefaultTimestepping_C", PetscViewerHDF5SetDefaultTimestepping_HDF5));
653   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5GetCompress_C", PetscViewerHDF5GetCompress_HDF5));
654   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerHDF5SetCompress_C", PetscViewerHDF5SetCompress_HDF5));
655   PetscFunctionReturn(PETSC_SUCCESS);
656 }
657 
658 /*@C
659   PetscViewerHDF5Open - Opens a file for HDF5 input/output as a `PETSCVIEWERHDF5` `PetscViewer`
660 
661   Collective
662 
663   Input Parameters:
664 + comm - MPI communicator
665 . name - name of file
666 - type - type of file
667 
668   Output Parameter:
669 . hdf5v - `PetscViewer` for HDF5 input/output to use with the specified file
670 
671   Options Database Keys:
672 + -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
673 - -viewer_hdf5_sp_output       - forces (if true) the viewer to write data in single precision independent on the precision of PetscReal
674 
675   Level: beginner
676 
677   Notes:
678   Reading is always available, regardless of the mode. Available modes are
679 .vb
680   FILE_MODE_READ - open existing HDF5 file for read only access, fail if file does not exist [H5Fopen() with H5F_ACC_RDONLY]
681   FILE_MODE_WRITE - if file exists, fully overwrite it, else create new HDF5 file [H5FcreateH5Fcreate() with H5F_ACC_TRUNC]
682   FILE_MODE_APPEND - if file exists, keep existing contents [H5Fopen() with H5F_ACC_RDWR], else create new HDF5 file [H5FcreateH5Fcreate() with H5F_ACC_EXCL]
683   FILE_MODE_UPDATE - same as FILE_MODE_APPEND
684 .ve
685 
686   In case of `FILE_MODE_APPEND` / `FILE_MODE_UPDATE`, any stored object (dataset, attribute) can be selectively overwritten if the same fully qualified name (/group/path/to/object) is specified.
687 
688   This PetscViewer should be destroyed with PetscViewerDestroy().
689 
690 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerHDF5SetBaseDimension2()`,
691           `PetscViewerHDF5SetSPOutput()`, `PetscViewerHDF5GetBaseDimension2()`, `VecView()`, `MatView()`, `VecLoad()`,
692           `MatLoad()`, `PetscFileMode`, `PetscViewer`, `PetscViewerSetType()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
693 @*/
PetscViewerHDF5Open(MPI_Comm comm,const char name[],PetscFileMode type,PetscViewer * hdf5v)694 PetscErrorCode PetscViewerHDF5Open(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *hdf5v)
695 {
696   PetscFunctionBegin;
697   PetscCall(PetscViewerCreate(comm, hdf5v));
698   PetscCall(PetscViewerSetType(*hdf5v, PETSCVIEWERHDF5));
699   PetscCall(PetscViewerFileSetMode(*hdf5v, type));
700   PetscCall(PetscViewerFileSetName(*hdf5v, name));
701   PetscCall(PetscViewerSetFromOptions(*hdf5v));
702   PetscFunctionReturn(PETSC_SUCCESS);
703 }
704 
705 /*@C
706   PetscViewerHDF5GetFileId - Retrieve the file id, this file ID then can be used in direct HDF5 calls
707 
708   Not Collective
709 
710   Input Parameter:
711 . viewer - the `PetscViewer`
712 
713   Output Parameter:
714 . file_id - The file id
715 
716   Level: intermediate
717 
718 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`
719 @*/
PetscViewerHDF5GetFileId(PetscViewer viewer,hid_t * file_id)720 PetscErrorCode PetscViewerHDF5GetFileId(PetscViewer viewer, hid_t *file_id)
721 {
722   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
723 
724   PetscFunctionBegin;
725   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
726   if (file_id) *file_id = hdf5->file_id;
727   PetscFunctionReturn(PETSC_SUCCESS);
728 }
729 
730 /*@C
731   PetscViewerHDF5PushGroup - Set the current HDF5 group for output
732 
733   Not Collective
734 
735   Input Parameters:
736 + viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
737 - name   - The group name
738 
739   Level: intermediate
740 
741   Notes:
742   This is designed to mnemonically resemble the Unix cd command.
743 .vb
744   If name begins with '/', it is interpreted as an absolute path fully replacing current group, otherwise it is taken as relative to the current group.
745   `NULL`, empty string, or any sequence of all slashes (e.g. "///") is interpreted as the root group "/".
746   "." means the current group is pushed again.
747 .ve
748 
749   Example:
750   Suppose the current group is "/a".
751 .vb
752   If name is `NULL`, empty string, or a sequence of all slashes (e.g. "///"), then the new group will be "/".
753   If name is ".", then the new group will be "/a".
754   If name is "b", then the new group will be "/a/b".
755   If name is "/b", then the new group will be "/b".
756 .ve
757 
758   Developer Notes:
759   The root group "/" is internally stored as `NULL`.
760 
761 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5OpenGroup()`, `PetscViewerHDF5WriteGroup()`
762 @*/
PetscViewerHDF5PushGroup(PetscViewer viewer,const char name[])763 PetscErrorCode PetscViewerHDF5PushGroup(PetscViewer viewer, const char name[])
764 {
765   PetscViewer_HDF5         *hdf5 = (PetscViewer_HDF5 *)viewer->data;
766   PetscViewerHDF5GroupList *groupNode;
767   size_t                    i, len;
768   char                      buf[PETSC_MAX_PATH_LEN];
769   const char               *gname;
770 
771   PetscFunctionBegin;
772   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
773   if (name) PetscAssertPointer(name, 2);
774   PetscCall(PetscStrlen(name, &len));
775   gname = NULL;
776   if (len) {
777     if (len == 1 && name[0] == '.') {
778       /* use current name */
779       gname = (hdf5->groups && hdf5->groups->name) ? hdf5->groups->name : NULL;
780     } else if (name[0] == '/') {
781       /* absolute */
782       for (i = 1; i < len; i++) {
783         if (name[i] != '/') {
784           gname = name;
785           break;
786         }
787       }
788     } else {
789       /* relative */
790       const char *parent = (hdf5->groups && hdf5->groups->name) ? hdf5->groups->name : "";
791       PetscCall(PetscSNPrintf(buf, sizeof(buf), "%s/%s", parent, name));
792       gname = buf;
793     }
794   }
795   PetscCall(PetscNew(&groupNode));
796   PetscCall(PetscStrallocpy(gname, (char **)&groupNode->name));
797   groupNode->next = hdf5->groups;
798   hdf5->groups    = groupNode;
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 /*@
803   PetscViewerHDF5PopGroup - Return the current HDF5 group for output to the previous value
804 
805   Not Collective
806 
807   Input Parameter:
808 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
809 
810   Level: intermediate
811 
812 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5OpenGroup()`, `PetscViewerHDF5WriteGroup()`
813 @*/
PetscViewerHDF5PopGroup(PetscViewer viewer)814 PetscErrorCode PetscViewerHDF5PopGroup(PetscViewer viewer)
815 {
816   PetscViewer_HDF5         *hdf5 = (PetscViewer_HDF5 *)viewer->data;
817   PetscViewerHDF5GroupList *groupNode;
818 
819   PetscFunctionBegin;
820   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
821   PetscCheck(hdf5->groups, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "HDF5 group stack is empty, cannot pop");
822   groupNode    = hdf5->groups;
823   hdf5->groups = hdf5->groups->next;
824   PetscCall(PetscFree(groupNode->name));
825   PetscCall(PetscFree(groupNode));
826   PetscFunctionReturn(PETSC_SUCCESS);
827 }
828 
PetscViewerHDF5GetGroup_Internal(PetscViewer viewer,const char * name[])829 static PetscErrorCode PetscViewerHDF5GetGroup_Internal(PetscViewer viewer, const char *name[])
830 {
831   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
832 
833   PetscFunctionBegin;
834   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
835   PetscAssertPointer(name, 2);
836   if (hdf5->groups) *name = hdf5->groups->name;
837   else *name = NULL;
838   PetscFunctionReturn(PETSC_SUCCESS);
839 }
840 
841 /*@C
842   PetscViewerHDF5OpenGroup - Open the HDF5 group with the name (full path) returned by `PetscViewerHDF5GetGroup()`,
843   and return this group's ID and file ID.
844   If `PetscViewerHDF5GetGroup()` yields NULL, then group ID is file ID.
845 
846   Not Collective
847 
848   Input Parameters:
849 + viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
850 - path   - (Optional) The path relative to the pushed group
851 
852   Output Parameters:
853 + fileId  - The HDF5 file ID
854 - groupId - The HDF5 group ID
855 
856   Level: intermediate
857 
858   Note:
859   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
860   `NULL` or empty path means the current pushed group.
861 
862   If the viewer is writable, the group is created if it doesn't exist yet.
863 
864 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5WriteGroup()`
865 @*/
PetscViewerHDF5OpenGroup(PetscViewer viewer,const char path[],hid_t * fileId,hid_t * groupId)866 PetscErrorCode PetscViewerHDF5OpenGroup(PetscViewer viewer, const char path[], hid_t *fileId, hid_t *groupId)
867 {
868   hid_t       file_id;
869   H5O_type_t  type;
870   const char *fileName  = NULL;
871   const char *groupName = NULL;
872   PetscBool   writable, has;
873 
874   PetscFunctionBegin;
875   PetscCall(PetscViewerWritable(viewer, &writable));
876   PetscCall(PetscViewerHDF5GetFileId(viewer, &file_id));
877   PetscCall(PetscViewerFileGetName(viewer, &fileName));
878   PetscCall(PetscViewerHDF5GetGroup(viewer, path, &groupName));
879   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, groupName, writable, &has, &type));
880   if (!has) {
881     PetscCheck(writable, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Group %s does not exist and file %s is not open for writing", groupName, fileName);
882     SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_LIB, "HDF5 failed to create group %s although file %s is open for writing", groupName, fileName);
883   }
884   PetscCheck(type == H5O_TYPE_GROUP, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Path %s in file %s resolves to something which is not a group", groupName, fileName);
885   PetscCallHDF5Return(*groupId, H5Gopen2, (file_id, groupName, H5P_DEFAULT));
886   PetscCall(PetscFree(groupName));
887   *fileId = file_id;
888   PetscFunctionReturn(PETSC_SUCCESS);
889 }
890 
891 /*@C
892   PetscViewerHDF5WriteGroup - Ensure the HDF5 group exists in the HDF5 file
893 
894   Not Collective
895 
896   Input Parameters:
897 + viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
898 - path   - (Optional) The path relative to the pushed group
899 
900   Level: intermediate
901 
902   Note:
903   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
904   `NULL` or empty path means the current pushed group.
905 
906   This will fail if the viewer is not writable.
907 
908 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5OpenGroup()`
909 @*/
PetscViewerHDF5WriteGroup(PetscViewer viewer,const char path[])910 PetscErrorCode PetscViewerHDF5WriteGroup(PetscViewer viewer, const char path[])
911 {
912   hid_t fileId, groupId;
913 
914   PetscFunctionBegin;
915   PetscCall(PetscViewerHDF5OpenGroup(viewer, path, &fileId, &groupId)); // make sure group is actually created
916   PetscCallHDF5(H5Gclose, (groupId));
917   PetscFunctionReturn(PETSC_SUCCESS);
918 }
919 
920 /*@
921   PetscViewerHDF5PushTimestepping - Activate timestepping mode for subsequent HDF5 reading and writing.
922 
923   Not Collective
924 
925   Input Parameter:
926 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
927 
928   Level: intermediate
929 
930   Notes:
931   On first `PetscViewerHDF5PushTimestepping()`, the initial time step is set to 0.
932   Next timesteps can then be set using `PetscViewerHDF5IncrementTimestep()` or `PetscViewerHDF5SetTimestep()`.
933   Current timestep value determines which timestep is read from or written to any dataset on the next HDF5 I/O operation [e.g. `VecView()`].
934   Use `PetscViewerHDF5PopTimestepping()` to deactivate timestepping mode; calling it by the end of the program is NOT mandatory.
935   Current timestep is remembered between `PetscViewerHDF5PopTimestepping()` and the next `PetscViewerHDF5PushTimestepping()`.
936 
937   If a dataset was stored with timestepping, it can be loaded only in the timestepping mode again.
938   Loading a timestepped dataset with timestepping disabled, or vice-versa results in an error.
939 
940   Developer Notes:
941   Timestepped HDF5 dataset has an extra dimension and attribute "timestepping" set to true.
942 
943 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PopTimestepping()`, `PetscViewerHDF5IsTimestepping()`, `PetscViewerHDF5SetTimestep()`, `PetscViewerHDF5IncrementTimestep()`, `PetscViewerHDF5GetTimestep()`
944 @*/
PetscViewerHDF5PushTimestepping(PetscViewer viewer)945 PetscErrorCode PetscViewerHDF5PushTimestepping(PetscViewer viewer)
946 {
947   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
948 
949   PetscFunctionBegin;
950   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
951   PetscCheck(!hdf5->timestepping, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping is already pushed");
952   hdf5->timestepping = PETSC_TRUE;
953   if (hdf5->timestep < 0) hdf5->timestep = 0;
954   PetscFunctionReturn(PETSC_SUCCESS);
955 }
956 
957 /*@
958   PetscViewerHDF5PopTimestepping - Deactivate timestepping mode for subsequent HDF5 reading and writing.
959 
960   Not Collective
961 
962   Input Parameter:
963 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
964 
965   Level: intermediate
966 
967   Note:
968   See `PetscViewerHDF5PushTimestepping()` for details.
969 
970 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5IsTimestepping()`, `PetscViewerHDF5SetTimestep()`, `PetscViewerHDF5IncrementTimestep()`, `PetscViewerHDF5GetTimestep()`
971 @*/
PetscViewerHDF5PopTimestepping(PetscViewer viewer)972 PetscErrorCode PetscViewerHDF5PopTimestepping(PetscViewer viewer)
973 {
974   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
975 
976   PetscFunctionBegin;
977   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
978   PetscCheck(hdf5->timestepping, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
979   hdf5->timestepping = PETSC_FALSE;
980   PetscFunctionReturn(PETSC_SUCCESS);
981 }
982 
983 /*@
984   PetscViewerHDF5IsTimestepping - Ask the viewer whether it is in timestepping mode currently.
985 
986   Not Collective
987 
988   Input Parameter:
989 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
990 
991   Output Parameter:
992 . flg - is timestepping active?
993 
994   Level: intermediate
995 
996   Note:
997   See `PetscViewerHDF5PushTimestepping()` for details.
998 
999 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5PopTimestepping()`, `PetscViewerHDF5SetTimestep()`, `PetscViewerHDF5IncrementTimestep()`, `PetscViewerHDF5GetTimestep()`
1000 @*/
PetscViewerHDF5IsTimestepping(PetscViewer viewer,PetscBool * flg)1001 PetscErrorCode PetscViewerHDF5IsTimestepping(PetscViewer viewer, PetscBool *flg)
1002 {
1003   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
1004 
1005   PetscFunctionBegin;
1006   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1007   *flg = hdf5->timestepping;
1008   PetscFunctionReturn(PETSC_SUCCESS);
1009 }
1010 
1011 /*@
1012   PetscViewerHDF5IncrementTimestep - Increments current timestep for the HDF5 output. Fields are stacked in time.
1013 
1014   Not Collective
1015 
1016   Input Parameter:
1017 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
1018 
1019   Level: intermediate
1020 
1021   Note:
1022   This can be called only if the viewer is in timestepping mode. See `PetscViewerHDF5PushTimestepping()` for details.
1023 
1024 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5SetTimestep()`, `PetscViewerHDF5GetTimestep()`
1025 @*/
PetscViewerHDF5IncrementTimestep(PetscViewer viewer)1026 PetscErrorCode PetscViewerHDF5IncrementTimestep(PetscViewer viewer)
1027 {
1028   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
1029 
1030   PetscFunctionBegin;
1031   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1032   PetscCheck(hdf5->timestepping, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
1033   ++hdf5->timestep;
1034   PetscFunctionReturn(PETSC_SUCCESS);
1035 }
1036 
1037 /*@
1038   PetscViewerHDF5SetTimestep - Set the current timestep for the HDF5 output. Fields are stacked in time.
1039 
1040   Logically Collective
1041 
1042   Input Parameters:
1043 + viewer   - the `PetscViewer` of type `PETSCVIEWERHDF5`
1044 - timestep - The timestep
1045 
1046   Level: intermediate
1047 
1048   Note:
1049   This can be called only if the viewer is in timestepping mode. See `PetscViewerHDF5PushTimestepping()` for details.
1050 
1051 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5IncrementTimestep()`, `PetscViewerHDF5GetTimestep()`
1052 @*/
PetscViewerHDF5SetTimestep(PetscViewer viewer,PetscInt timestep)1053 PetscErrorCode PetscViewerHDF5SetTimestep(PetscViewer viewer, PetscInt timestep)
1054 {
1055   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
1056 
1057   PetscFunctionBegin;
1058   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1059   PetscValidLogicalCollectiveInt(viewer, timestep, 2);
1060   PetscCheck(timestep >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestep %" PetscInt_FMT " is negative", timestep);
1061   PetscCheck(hdf5->timestepping, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
1062   hdf5->timestep = timestep;
1063   PetscFunctionReturn(PETSC_SUCCESS);
1064 }
1065 
1066 /*@
1067   PetscViewerHDF5GetTimestep - Get the current timestep for the HDF5 output. Fields are stacked in time.
1068 
1069   Not Collective
1070 
1071   Input Parameter:
1072 . viewer - the `PetscViewer` of type `PETSCVIEWERHDF5`
1073 
1074   Output Parameter:
1075 . timestep - The timestep
1076 
1077   Level: intermediate
1078 
1079   Note:
1080   This can be called only if the viewer is in the timestepping mode. See `PetscViewerHDF5PushTimestepping()` for details.
1081 
1082 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5PushTimestepping()`, `PetscViewerHDF5IncrementTimestep()`, `PetscViewerHDF5SetTimestep()`
1083 @*/
PetscViewerHDF5GetTimestep(PetscViewer viewer,PetscInt * timestep)1084 PetscErrorCode PetscViewerHDF5GetTimestep(PetscViewer viewer, PetscInt *timestep)
1085 {
1086   PetscViewer_HDF5 *hdf5 = (PetscViewer_HDF5 *)viewer->data;
1087 
1088   PetscFunctionBegin;
1089   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1090   PetscAssertPointer(timestep, 2);
1091   PetscCheck(hdf5->timestepping, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Timestepping has not been pushed yet. Call PetscViewerHDF5PushTimestepping() first");
1092   *timestep = hdf5->timestep;
1093   PetscFunctionReturn(PETSC_SUCCESS);
1094 }
1095 
1096 /*@C
1097   PetscDataTypeToHDF5DataType - Converts the PETSc name of a datatype to its HDF5 name.
1098 
1099   Not Collective
1100 
1101   Input Parameter:
1102 . ptype - the PETSc datatype name (for example `PETSC_DOUBLE`)
1103 
1104   Output Parameter:
1105 . htype - the HDF5  datatype
1106 
1107   Level: advanced
1108 
1109 .seealso: [](sec_viewers), `PetscDataType`, `PetscHDF5DataTypeToPetscDataType()`
1110 @*/
PetscDataTypeToHDF5DataType(PetscDataType ptype,hid_t * htype)1111 PetscErrorCode PetscDataTypeToHDF5DataType(PetscDataType ptype, hid_t *htype)
1112 {
1113   PetscFunctionBegin;
1114   if (ptype == PETSC_INT) *htype = PetscDefined(USE_64BIT_INDICES) ? H5T_NATIVE_LLONG : H5T_NATIVE_INT;
1115   else if (ptype == PETSC_DOUBLE) *htype = H5T_NATIVE_DOUBLE;
1116   else if (ptype == PETSC_LONG) *htype = H5T_NATIVE_LONG;
1117   else if (ptype == PETSC_SHORT) *htype = H5T_NATIVE_SHORT;
1118   else if (ptype == PETSC_ENUM) *htype = H5T_NATIVE_INT;
1119   else if (ptype == PETSC_BOOL) *htype = H5T_NATIVE_HBOOL;
1120   else if (ptype == PETSC_FLOAT) *htype = H5T_NATIVE_FLOAT;
1121   else if (ptype == PETSC_CHAR) *htype = H5T_NATIVE_CHAR;
1122   else if (ptype == PETSC_BIT_LOGICAL) *htype = H5T_NATIVE_UCHAR;
1123   else if (ptype == PETSC_STRING) *htype = H5Tcopy(H5T_C_S1);
1124   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PETSc datatype");
1125   PetscFunctionReturn(PETSC_SUCCESS);
1126 }
1127 
1128 /*@C
1129   PetscHDF5DataTypeToPetscDataType - Finds the PETSc name of a datatype from its HDF5 name
1130 
1131   Not Collective
1132 
1133   Input Parameter:
1134 . htype - the HDF5 datatype (for example `H5T_NATIVE_DOUBLE`, ...)
1135 
1136   Output Parameter:
1137 . ptype - the PETSc datatype name (for example `PETSC_DOUBLE`)
1138 
1139   Level: advanced
1140 
1141 .seealso: [](sec_viewers), `PetscDataType`
1142 @*/
PetscHDF5DataTypeToPetscDataType(hid_t htype,PetscDataType * ptype)1143 PetscErrorCode PetscHDF5DataTypeToPetscDataType(hid_t htype, PetscDataType *ptype)
1144 {
1145   PetscFunctionBegin;
1146   if (htype == H5T_NATIVE_INT) *ptype = PetscDefined(USE_64BIT_INDICES) ? PETSC_LONG : PETSC_INT;
1147 #if defined(PETSC_USE_64BIT_INDICES)
1148   else if (htype == H5T_NATIVE_LLONG) *ptype = PETSC_INT;
1149 #endif
1150   else if (htype == H5T_NATIVE_DOUBLE) *ptype = PETSC_DOUBLE;
1151   else if (htype == H5T_NATIVE_LONG) *ptype = PETSC_LONG;
1152   else if (htype == H5T_NATIVE_SHORT) *ptype = PETSC_SHORT;
1153   else if (htype == H5T_NATIVE_HBOOL) *ptype = PETSC_BOOL;
1154   else if (htype == H5T_NATIVE_FLOAT) *ptype = PETSC_FLOAT;
1155   else if (htype == H5T_NATIVE_CHAR) *ptype = PETSC_CHAR;
1156   else if (htype == H5T_NATIVE_UCHAR) *ptype = PETSC_CHAR;
1157   else if (htype == H5T_C_S1) *ptype = PETSC_STRING;
1158   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype");
1159   PetscFunctionReturn(PETSC_SUCCESS);
1160 }
1161 
1162 /*@C
1163   PetscViewerHDF5WriteAttribute - Write an attribute
1164 
1165   Collective
1166 
1167   Input Parameters:
1168 + viewer   - The `PETSCVIEWERHDF5` viewer
1169 . parent   - The parent dataset/group name
1170 . name     - The attribute name
1171 . datatype - The attribute type
1172 - value    - The attribute value
1173 
1174   Level: advanced
1175 
1176   Note:
1177   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. NULL means the current pushed group.
1178 
1179 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5ReadAttribute()`, `PetscViewerHDF5HasAttribute()`,
1180           `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1181 @*/
PetscViewerHDF5WriteAttribute(PetscViewer viewer,const char parent[],const char name[],PetscDataType datatype,const void * value)1182 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value)
1183 {
1184   const char *parentAbsPath;
1185   hid_t       h5, dataspace, obj, attribute, dtype;
1186   PetscBool   has;
1187 
1188   PetscFunctionBegin;
1189   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1190   if (parent) PetscAssertPointer(parent, 2);
1191   PetscAssertPointer(name, 3);
1192   PetscValidLogicalCollectiveEnum(viewer, datatype, 4);
1193   PetscAssertPointer(value, 5);
1194   PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath));
1195   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_TRUE, NULL, NULL));
1196   PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has));
1197   PetscCall(PetscDataTypeToHDF5DataType(datatype, &dtype));
1198   if (datatype == PETSC_STRING) {
1199     size_t len;
1200     PetscCall(PetscStrlen((const char *)value, &len));
1201     PetscCallHDF5(H5Tset_size, (dtype, len + 1));
1202   }
1203   PetscCall(PetscViewerHDF5GetFileId(viewer, &h5));
1204   PetscCallHDF5Return(dataspace, H5Screate, (H5S_SCALAR));
1205   PetscCallHDF5Return(obj, H5Oopen, (h5, parentAbsPath, H5P_DEFAULT));
1206   if (has) {
1207     PetscCallHDF5Return(attribute, H5Aopen_name, (obj, name));
1208   } else {
1209     PetscCallHDF5Return(attribute, H5Acreate2, (obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT));
1210   }
1211   PetscCallHDF5(H5Awrite, (attribute, dtype, value));
1212   if (datatype == PETSC_STRING) PetscCallHDF5(H5Tclose, (dtype));
1213   PetscCallHDF5(H5Aclose, (attribute));
1214   PetscCallHDF5(H5Oclose, (obj));
1215   PetscCallHDF5(H5Sclose, (dataspace));
1216   PetscCall(PetscFree(parentAbsPath));
1217   PetscFunctionReturn(PETSC_SUCCESS);
1218 }
1219 
1220 /*@C
1221   PetscViewerHDF5WriteObjectAttribute - Write an attribute to the dataset matching the given `PetscObject` by name
1222 
1223   Collective
1224 
1225   Input Parameters:
1226 + viewer   - The `PETSCVIEWERHDF5` viewer
1227 . obj      - The object whose name is used to lookup the parent dataset, relative to the current group.
1228 . name     - The attribute name
1229 . datatype - The attribute type
1230 - value    - The attribute value
1231 
1232   Level: advanced
1233 
1234   Note:
1235   This fails if the path current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1236   You might want to check first if it does using `PetscViewerHDF5HasObject()`.
1237 
1238 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5HasObjectAttribute()`,
1239           `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1240 @*/
PetscViewerHDF5WriteObjectAttribute(PetscViewer viewer,PetscObject obj,const char name[],PetscDataType datatype,const void * value)1241 PetscErrorCode PetscViewerHDF5WriteObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, const void *value)
1242 {
1243   PetscFunctionBegin;
1244   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1245   PetscValidHeader(obj, 2);
1246   PetscAssertPointer(name, 3);
1247   PetscAssertPointer(value, 5);
1248   PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj));
1249   PetscCall(PetscViewerHDF5WriteAttribute(viewer, obj->name, name, datatype, value));
1250   PetscFunctionReturn(PETSC_SUCCESS);
1251 }
1252 
1253 /*@C
1254   PetscViewerHDF5ReadAttribute - Read an attribute
1255 
1256   Collective
1257 
1258   Input Parameters:
1259 + viewer       - The `PETSCVIEWERHDF5` viewer
1260 . parent       - The parent dataset/group name
1261 . name         - The attribute name
1262 . datatype     - The attribute type
1263 - defaultValue - The pointer to the default value
1264 
1265   Output Parameter:
1266 . value - The pointer to the read HDF5 attribute value
1267 
1268   Level: advanced
1269 
1270   Notes:
1271   If defaultValue is `NULL` and the attribute is not found, an error occurs.
1272 
1273   If defaultValue is not `NULL` and the attribute is not found, `defaultValue` is copied to value.
1274 
1275   The pointers `defaultValue` and value can be the same; for instance
1276 .vb
1277   flg = PETSC_FALSE;
1278   PetscCall(`PetscViewerHDF5ReadAttribute`(viewer,name,"attr",PETSC_BOOL,&flg,&flg));
1279 .ve
1280   is valid, but make sure the default value is initialized.
1281 
1282   If the datatype is `PETSC_STRING`, the output string is newly allocated so one must `PetscFree()` it when no longer needed.
1283 
1284   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. `NULL` means the current pushed group.
1285 
1286 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1287 @*/
PetscViewerHDF5ReadAttribute(PetscViewer viewer,const char parent[],const char name[],PetscDataType datatype,const void * defaultValue,void * value)1288 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *defaultValue, void *value)
1289 {
1290   const char *parentAbsPath;
1291   hid_t       h5, obj, attribute, dtype;
1292   PetscBool   has;
1293 
1294   PetscFunctionBegin;
1295   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1296   if (parent) PetscAssertPointer(parent, 2);
1297   PetscAssertPointer(name, 3);
1298   if (defaultValue) PetscAssertPointer(defaultValue, 5);
1299   PetscAssertPointer(value, 6);
1300   PetscCall(PetscDataTypeToHDF5DataType(datatype, &dtype));
1301   PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath));
1302   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, &has, NULL));
1303   if (has) PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has));
1304   if (!has) {
1305     if (defaultValue) {
1306       if (defaultValue != value) {
1307         if (datatype == PETSC_STRING) {
1308           PetscCall(PetscStrallocpy(*(char **)defaultValue, (char **)value));
1309         } else {
1310           size_t len;
1311           PetscCallHDF5ReturnNoCheck(len, H5Tget_size, (dtype));
1312           PetscCall(PetscMemcpy(value, defaultValue, len));
1313         }
1314       }
1315       PetscCall(PetscFree(parentAbsPath));
1316       PetscFunctionReturn(PETSC_SUCCESS);
1317     } else SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Attribute %s/%s does not exist and default value not provided", parentAbsPath, name);
1318   }
1319   PetscCall(PetscViewerHDF5GetFileId(viewer, &h5));
1320   PetscCallHDF5Return(obj, H5Oopen, (h5, parentAbsPath, H5P_DEFAULT));
1321   PetscCallHDF5Return(attribute, H5Aopen_name, (obj, name));
1322   if (datatype == PETSC_STRING) {
1323     size_t len;
1324     hid_t  atype;
1325     PetscCallHDF5Return(atype, H5Aget_type, (attribute));
1326     PetscCallHDF5ReturnNoCheck(len, H5Tget_size, (atype));
1327     PetscCall(PetscMalloc((len + 1) * sizeof(char), value));
1328     PetscCallHDF5(H5Tset_size, (dtype, len + 1));
1329     PetscCallHDF5(H5Aread, (attribute, dtype, *(char **)value));
1330   } else {
1331     PetscCallHDF5(H5Aread, (attribute, dtype, value));
1332   }
1333   PetscCallHDF5(H5Aclose, (attribute));
1334   /* H5Oclose can be used to close groups, datasets, or committed datatypes */
1335   PetscCallHDF5(H5Oclose, (obj));
1336   PetscCall(PetscFree(parentAbsPath));
1337   PetscFunctionReturn(PETSC_SUCCESS);
1338 }
1339 
1340 /*@C
1341   PetscViewerHDF5ReadObjectAttribute - Read an attribute from the dataset matching the given `PetscObject` by name
1342 
1343   Collective
1344 
1345   Input Parameters:
1346 + viewer       - The `PETSCVIEWERHDF5` viewer
1347 . obj          - The object whose name is used to lookup the parent dataset, relative to the current group.
1348 . name         - The attribute name
1349 . datatype     - The attribute type
1350 - defaultValue - The default attribute value
1351 
1352   Output Parameter:
1353 . value - The attribute value
1354 
1355   Level: advanced
1356 
1357   Note:
1358   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1359   You might want to check first if it does using `PetscViewerHDF5HasObject()`.
1360 
1361 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5ReadAttribute()` `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5HasObjectAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1362 @*/
PetscViewerHDF5ReadObjectAttribute(PetscViewer viewer,PetscObject obj,const char name[],PetscDataType datatype,void * defaultValue,void * value)1363 PetscErrorCode PetscViewerHDF5ReadObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, void *defaultValue, void *value)
1364 {
1365   PetscFunctionBegin;
1366   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1367   PetscValidHeader(obj, 2);
1368   PetscAssertPointer(name, 3);
1369   PetscAssertPointer(value, 6);
1370   PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj));
1371   PetscCall(PetscViewerHDF5ReadAttribute(viewer, obj->name, name, datatype, defaultValue, value));
1372   PetscFunctionReturn(PETSC_SUCCESS);
1373 }
1374 
PetscViewerHDF5Traverse_Inner_Internal(hid_t h5,const char name[],PetscBool createGroup,PetscBool * exists_)1375 static PetscErrorCode PetscViewerHDF5Traverse_Inner_Internal(hid_t h5, const char name[], PetscBool createGroup, PetscBool *exists_)
1376 {
1377   htri_t exists;
1378   hid_t  group;
1379 
1380   PetscFunctionBegin;
1381   PetscCallHDF5Return(exists, H5Lexists, (h5, name, H5P_DEFAULT));
1382   if (exists) PetscCallHDF5Return(exists, H5Oexists_by_name, (h5, name, H5P_DEFAULT));
1383   if (!exists && createGroup) {
1384     PetscCallHDF5Return(group, H5Gcreate2, (h5, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
1385     PetscCallHDF5(H5Gclose, (group));
1386     exists = PETSC_TRUE;
1387   }
1388   *exists_ = (PetscBool)exists;
1389   PetscFunctionReturn(PETSC_SUCCESS);
1390 }
1391 
PetscViewerHDF5Traverse_Internal(PetscViewer viewer,const char name[],PetscBool createGroup,PetscBool * has,H5O_type_t * otype)1392 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer viewer, const char name[], PetscBool createGroup, PetscBool *has, H5O_type_t *otype)
1393 {
1394   const char rootGroupName[] = "/";
1395   hid_t      h5;
1396   PetscBool  exists = PETSC_FALSE;
1397   PetscInt   i;
1398   int        n;
1399   char     **hierarchy;
1400   char       buf[PETSC_MAX_PATH_LEN] = "";
1401 
1402   PetscFunctionBegin;
1403   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1404   if (name) PetscAssertPointer(name, 2);
1405   else name = rootGroupName;
1406   if (has) {
1407     PetscAssertPointer(has, 4);
1408     *has = PETSC_FALSE;
1409   }
1410   if (otype) {
1411     PetscAssertPointer(otype, 5);
1412     *otype = H5O_TYPE_UNKNOWN;
1413   }
1414   PetscCall(PetscViewerHDF5GetFileId(viewer, &h5));
1415 
1416   /*
1417      Unfortunately, H5Oexists_by_name() fails if any object in hierarchy is missing.
1418      Hence, each of them needs to be tested separately:
1419      1) whether it's a valid link
1420      2) whether this link resolves to an object
1421      See H5Oexists_by_name() documentation.
1422   */
1423   PetscCall(PetscStrToArray(name, '/', &n, &hierarchy));
1424   if (!n) {
1425     /*  Assume group "/" always exists in accordance with HDF5 >= 1.10.0. See H5Lexists() documentation. */
1426     if (has) *has = PETSC_TRUE;
1427     if (otype) *otype = H5O_TYPE_GROUP;
1428     PetscCall(PetscStrToArrayDestroy(n, hierarchy));
1429     PetscFunctionReturn(PETSC_SUCCESS);
1430   }
1431   for (i = 0; i < n; i++) {
1432     PetscCall(PetscStrlcat(buf, "/", sizeof(buf)));
1433     PetscCall(PetscStrlcat(buf, hierarchy[i], sizeof(buf)));
1434     PetscCall(PetscViewerHDF5Traverse_Inner_Internal(h5, buf, createGroup, &exists));
1435     if (!exists) break;
1436   }
1437   PetscCall(PetscStrToArrayDestroy(n, hierarchy));
1438 
1439   /* If the object exists, get its type */
1440   if (exists && otype) {
1441     H5O_info_t info;
1442 
1443     /* We could use H5Iget_type() here but that would require opening the object. This way we only need its name. */
1444     PetscCallHDF5(H5Oget_info_by_name, (h5, name, &info, H5P_DEFAULT));
1445     *otype = info.type;
1446   }
1447   if (has) *has = exists;
1448   PetscFunctionReturn(PETSC_SUCCESS);
1449 }
1450 
1451 /*@C
1452   PetscViewerHDF5HasGroup - Check whether the current (pushed) group exists in the HDF5 file
1453 
1454   Collective
1455 
1456   Input Parameters:
1457 + viewer - The `PETSCVIEWERHDF5` viewer
1458 - path   - (Optional) The path relative to the pushed group
1459 
1460   Output Parameter:
1461 . has - Flag for group existence
1462 
1463   Level: advanced
1464 
1465   Notes:
1466   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
1467   `NULL` or empty path means the current pushed group.
1468 
1469   If path exists but is not a group, `PETSC_FALSE` is returned.
1470 
1471 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasDataset()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5OpenGroup()`
1472 @*/
PetscViewerHDF5HasGroup(PetscViewer viewer,const char path[],PetscBool * has)1473 PetscErrorCode PetscViewerHDF5HasGroup(PetscViewer viewer, const char path[], PetscBool *has)
1474 {
1475   H5O_type_t  type;
1476   const char *abspath;
1477 
1478   PetscFunctionBegin;
1479   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1480   if (path) PetscAssertPointer(path, 2);
1481   PetscAssertPointer(has, 3);
1482   PetscCall(PetscViewerHDF5GetGroup(viewer, path, &abspath));
1483   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type));
1484   *has = (PetscBool)(type == H5O_TYPE_GROUP);
1485   PetscCall(PetscFree(abspath));
1486   PetscFunctionReturn(PETSC_SUCCESS);
1487 }
1488 
1489 /*@C
1490   PetscViewerHDF5HasDataset - Check whether a given dataset exists in the HDF5 file
1491 
1492   Collective
1493 
1494   Input Parameters:
1495 + viewer - The `PETSCVIEWERHDF5` viewer
1496 - path   - The dataset path
1497 
1498   Output Parameter:
1499 . has - Flag whether dataset exists
1500 
1501   Level: advanced
1502 
1503   Notes:
1504   If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group.
1505 
1506   If `path` is `NULL` or empty, has is set to `PETSC_FALSE`.
1507 
1508   If `path` exists but is not a dataset, has is set to `PETSC_FALSE` as well.
1509 
1510 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasGroup()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1511 @*/
PetscViewerHDF5HasDataset(PetscViewer viewer,const char path[],PetscBool * has)1512 PetscErrorCode PetscViewerHDF5HasDataset(PetscViewer viewer, const char path[], PetscBool *has)
1513 {
1514   H5O_type_t  type;
1515   const char *abspath;
1516 
1517   PetscFunctionBegin;
1518   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1519   if (path) PetscAssertPointer(path, 2);
1520   PetscAssertPointer(has, 3);
1521   PetscCall(PetscViewerHDF5GetGroup(viewer, path, &abspath));
1522   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type));
1523   *has = (PetscBool)(type == H5O_TYPE_DATASET);
1524   PetscCall(PetscFree(abspath));
1525   PetscFunctionReturn(PETSC_SUCCESS);
1526 }
1527 
1528 /*@
1529   PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file under current group
1530 
1531   Collective
1532 
1533   Input Parameters:
1534 + viewer - The `PETSCVIEWERHDF5` viewer
1535 - obj    - The named object
1536 
1537   Output Parameter:
1538 . has - Flag for dataset existence
1539 
1540   Level: advanced
1541 
1542   Notes:
1543   If the object is unnamed, an error occurs.
1544 
1545   If the path current_group/object_name exists but is not a dataset, has is set to `PETSC_FALSE` as well.
1546 
1547 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasDataset()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1548 @*/
PetscViewerHDF5HasObject(PetscViewer viewer,PetscObject obj,PetscBool * has)1549 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has)
1550 {
1551   size_t len;
1552 
1553   PetscFunctionBegin;
1554   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1555   PetscValidHeader(obj, 2);
1556   PetscAssertPointer(has, 3);
1557   PetscCall(PetscStrlen(obj->name, &len));
1558   PetscCheck(len, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Object must be named");
1559   PetscCall(PetscViewerHDF5HasDataset(viewer, obj->name, has));
1560   PetscFunctionReturn(PETSC_SUCCESS);
1561 }
1562 
1563 /*@C
1564   PetscViewerHDF5HasAttribute - Check whether an attribute exists
1565 
1566   Collective
1567 
1568   Input Parameters:
1569 + viewer - The `PETSCVIEWERHDF5` viewer
1570 . parent - The parent dataset/group name
1571 - name   - The attribute name
1572 
1573   Output Parameter:
1574 . has - Flag for attribute existence
1575 
1576   Level: advanced
1577 
1578   Note:
1579   If parent starts with '/', it is taken as an absolute path overriding currently pushed group, else parent is relative to the current pushed group. `NULL` means the current pushed group.
1580 
1581 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasObjectAttribute()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5ReadAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1582 @*/
PetscViewerHDF5HasAttribute(PetscViewer viewer,const char parent[],const char name[],PetscBool * has)1583 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1584 {
1585   const char *parentAbsPath;
1586 
1587   PetscFunctionBegin;
1588   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1589   if (parent) PetscAssertPointer(parent, 2);
1590   PetscAssertPointer(name, 3);
1591   PetscAssertPointer(has, 4);
1592   PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath));
1593   PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, has, NULL));
1594   if (*has) PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, has));
1595   PetscCall(PetscFree(parentAbsPath));
1596   PetscFunctionReturn(PETSC_SUCCESS);
1597 }
1598 
1599 /*@C
1600   PetscViewerHDF5HasObjectAttribute - Check whether an attribute is attached to the dataset matching the given `PetscObject` by name
1601 
1602   Collective
1603 
1604   Input Parameters:
1605 + viewer - The `PETSCVIEWERHDF5` viewer
1606 . obj    - The object whose name is used to lookup the parent dataset, relative to the current group.
1607 - name   - The attribute name
1608 
1609   Output Parameter:
1610 . has - Flag for attribute existence
1611 
1612   Level: advanced
1613 
1614   Note:
1615   This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset).
1616   You might want to check first if it does using `PetscViewerHDF5HasObject()`.
1617 
1618 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`
1619 @*/
PetscViewerHDF5HasObjectAttribute(PetscViewer viewer,PetscObject obj,const char name[],PetscBool * has)1620 PetscErrorCode PetscViewerHDF5HasObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscBool *has)
1621 {
1622   PetscFunctionBegin;
1623   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1624   PetscValidHeader(obj, 2);
1625   PetscAssertPointer(name, 3);
1626   PetscAssertPointer(has, 4);
1627   PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj));
1628   PetscCall(PetscViewerHDF5HasAttribute(viewer, obj->name, name, has));
1629   PetscFunctionReturn(PETSC_SUCCESS);
1630 }
1631 
PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer,const char parent[],const char name[],PetscBool * has)1632 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has)
1633 {
1634   hid_t  h5;
1635   htri_t hhas;
1636 
1637   PetscFunctionBegin;
1638   PetscCall(PetscViewerHDF5GetFileId(viewer, &h5));
1639   PetscCallHDF5Return(hhas, H5Aexists_by_name, (h5, parent, name, H5P_DEFAULT));
1640   *has = hhas ? PETSC_TRUE : PETSC_FALSE;
1641   PetscFunctionReturn(PETSC_SUCCESS);
1642 }
1643 
1644 /*
1645   The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that
1646   is attached to a communicator, in this case the attribute is a PetscViewer.
1647 */
1648 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID;
1649 
1650 /*@C
1651   PETSC_VIEWER_HDF5_ - Creates an `PETSCVIEWERHDF5` `PetscViewer` shared by all processors in a communicator.
1652 
1653   Collective
1654 
1655   Input Parameter:
1656 . comm - the MPI communicator to share the `PETSCVIEWERHDF5` `PetscViewer`
1657 
1658   Options Database Key:
1659 . -viewer_hdf5_filename <name> - name of the HDF5 file
1660 
1661   Environmental variable:
1662 . `PETSC_VIEWER_HDF5_FILENAME` - name of the HDF5 file
1663 
1664   Level: intermediate
1665 
1666   Note:
1667   Unlike almost all other PETSc routines, `PETSC_VIEWER_HDF5_()` does not return
1668   an error code.  The HDF5 `PetscViewer` is usually used in the form
1669 .vb
1670   XXXView(XXX object, PETSC_VIEWER_HDF5_(comm));
1671 .ve
1672 
1673 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerCreate()`, `PetscViewerDestroy()`
1674 @*/
PETSC_VIEWER_HDF5_(MPI_Comm comm)1675 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm)
1676 {
1677   PetscErrorCode ierr;
1678   PetscMPIInt    mpi_ierr;
1679   PetscBool      flg;
1680   PetscMPIInt    iflg;
1681   PetscViewer    viewer;
1682   char           fname[PETSC_MAX_PATH_LEN];
1683   MPI_Comm       ncomm;
1684 
1685   PetscFunctionBegin;
1686   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
1687   if (ierr) {
1688     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
1689     PetscFunctionReturn(NULL);
1690   }
1691   if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) {
1692     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_HDF5_keyval, NULL);
1693     if (mpi_ierr) {
1694       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
1695       PetscFunctionReturn(NULL);
1696     }
1697   }
1698   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_HDF5_keyval, (void **)&viewer, &iflg);
1699   if (mpi_ierr) {
1700     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
1701     PetscFunctionReturn(NULL);
1702   }
1703   if (!iflg) { /* PetscViewer not yet created */
1704     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_HDF5_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
1705     if (ierr) {
1706       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
1707       PetscFunctionReturn(NULL);
1708     }
1709     if (!flg) {
1710       ierr = PetscStrncpy(fname, "output.h5", sizeof(fname));
1711       if (ierr) {
1712         ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
1713         PetscFunctionReturn(NULL);
1714       }
1715     }
1716     ierr = PetscViewerHDF5Open(ncomm, fname, FILE_MODE_WRITE, &viewer);
1717     if (ierr) {
1718       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
1719       PetscFunctionReturn(NULL);
1720     }
1721     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
1722     if (ierr) {
1723       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
1724       PetscFunctionReturn(NULL);
1725     }
1726     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_HDF5_keyval, (void *)viewer);
1727     if (mpi_ierr) {
1728       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
1729       PetscFunctionReturn(NULL);
1730     }
1731   }
1732   ierr = PetscCommDestroy(&ncomm);
1733   if (ierr) {
1734     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
1735     PetscFunctionReturn(NULL);
1736   }
1737   PetscFunctionReturn(viewer);
1738 }
1739