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: }