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