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