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