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