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_INT; 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_FLOAT) *ptype = PETSC_FLOAT; 1161 else if (htype == H5T_NATIVE_CHAR) *ptype = PETSC_CHAR; 1162 else if (htype == H5T_NATIVE_UCHAR) *ptype = PETSC_CHAR; 1163 else if (htype == H5T_C_S1) *ptype = PETSC_STRING; 1164 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported HDF5 datatype"); 1165 PetscFunctionReturn(PETSC_SUCCESS); 1166 } 1167 1168 /*@C 1169 PetscViewerHDF5WriteAttribute - Write an attribute 1170 1171 Collective 1172 1173 Input Parameters: 1174 + viewer - The `PETSCVIEWERHDF5` viewer 1175 . parent - The parent dataset/group name 1176 . name - The attribute name 1177 . datatype - The attribute type 1178 - value - The attribute value 1179 1180 Level: advanced 1181 1182 Note: 1183 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. 1184 1185 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5ReadAttribute()`, `PetscViewerHDF5HasAttribute()`, 1186 `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1187 @*/ 1188 PetscErrorCode PetscViewerHDF5WriteAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *value) 1189 { 1190 const char *parentAbsPath; 1191 hid_t h5, dataspace, obj, attribute, dtype; 1192 PetscBool has; 1193 1194 PetscFunctionBegin; 1195 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1196 if (parent) PetscAssertPointer(parent, 2); 1197 PetscAssertPointer(name, 3); 1198 PetscValidLogicalCollectiveEnum(viewer, datatype, 4); 1199 PetscAssertPointer(value, 5); 1200 PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath)); 1201 PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_TRUE, NULL, NULL)); 1202 PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has)); 1203 PetscCall(PetscDataTypeToHDF5DataType(datatype, &dtype)); 1204 if (datatype == PETSC_STRING) { 1205 size_t len; 1206 PetscCall(PetscStrlen((const char *)value, &len)); 1207 PetscCallHDF5(H5Tset_size, (dtype, len + 1)); 1208 } 1209 PetscCall(PetscViewerHDF5GetFileId(viewer, &h5)); 1210 PetscCallHDF5Return(dataspace, H5Screate, (H5S_SCALAR)); 1211 PetscCallHDF5Return(obj, H5Oopen, (h5, parentAbsPath, H5P_DEFAULT)); 1212 if (has) { 1213 PetscCallHDF5Return(attribute, H5Aopen_name, (obj, name)); 1214 } else { 1215 PetscCallHDF5Return(attribute, H5Acreate2, (obj, name, dtype, dataspace, H5P_DEFAULT, H5P_DEFAULT)); 1216 } 1217 PetscCallHDF5(H5Awrite, (attribute, dtype, value)); 1218 if (datatype == PETSC_STRING) PetscCallHDF5(H5Tclose, (dtype)); 1219 PetscCallHDF5(H5Aclose, (attribute)); 1220 PetscCallHDF5(H5Oclose, (obj)); 1221 PetscCallHDF5(H5Sclose, (dataspace)); 1222 PetscCall(PetscFree(parentAbsPath)); 1223 PetscFunctionReturn(PETSC_SUCCESS); 1224 } 1225 1226 /*@C 1227 PetscViewerHDF5WriteObjectAttribute - Write an attribute to the dataset matching the given `PetscObject` by name 1228 1229 Collective 1230 1231 Input Parameters: 1232 + viewer - The `PETSCVIEWERHDF5` viewer 1233 . obj - The object whose name is used to lookup the parent dataset, relative to the current group. 1234 . name - The attribute name 1235 . datatype - The attribute type 1236 - value - The attribute value 1237 1238 Level: advanced 1239 1240 Note: 1241 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). 1242 You might want to check first if it does using `PetscViewerHDF5HasObject()`. 1243 1244 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5HasObjectAttribute()`, 1245 `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1246 @*/ 1247 PetscErrorCode PetscViewerHDF5WriteObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, const void *value) 1248 { 1249 PetscFunctionBegin; 1250 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1251 PetscValidHeader(obj, 2); 1252 PetscAssertPointer(name, 3); 1253 PetscAssertPointer(value, 5); 1254 PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj)); 1255 PetscCall(PetscViewerHDF5WriteAttribute(viewer, obj->name, name, datatype, value)); 1256 PetscFunctionReturn(PETSC_SUCCESS); 1257 } 1258 1259 /*@C 1260 PetscViewerHDF5ReadAttribute - Read an attribute 1261 1262 Collective 1263 1264 Input Parameters: 1265 + viewer - The `PETSCVIEWERHDF5` viewer 1266 . parent - The parent dataset/group name 1267 . name - The attribute name 1268 . datatype - The attribute type 1269 - defaultValue - The pointer to the default value 1270 1271 Output Parameter: 1272 . value - The pointer to the read HDF5 attribute value 1273 1274 Level: advanced 1275 1276 Notes: 1277 If defaultValue is `NULL` and the attribute is not found, an error occurs. 1278 1279 If defaultValue is not `NULL` and the attribute is not found, `defaultValue` is copied to value. 1280 1281 The pointers `defaultValue` and value can be the same; for instance 1282 .vb 1283 flg = PETSC_FALSE; 1284 PetscCall(`PetscViewerHDF5ReadAttribute`(viewer,name,"attr",PETSC_BOOL,&flg,&flg)); 1285 .ve 1286 is valid, but make sure the default value is initialized. 1287 1288 If the datatype is `PETSC_STRING`, the output string is newly allocated so one must `PetscFree()` it when no longer needed. 1289 1290 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. 1291 1292 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1293 @*/ 1294 PetscErrorCode PetscViewerHDF5ReadAttribute(PetscViewer viewer, const char parent[], const char name[], PetscDataType datatype, const void *defaultValue, void *value) 1295 { 1296 const char *parentAbsPath; 1297 hid_t h5, obj, attribute, dtype; 1298 PetscBool has; 1299 1300 PetscFunctionBegin; 1301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1302 if (parent) PetscAssertPointer(parent, 2); 1303 PetscAssertPointer(name, 3); 1304 if (defaultValue) PetscAssertPointer(defaultValue, 5); 1305 PetscAssertPointer(value, 6); 1306 PetscCall(PetscDataTypeToHDF5DataType(datatype, &dtype)); 1307 PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath)); 1308 PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, &has, NULL)); 1309 if (has) PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, &has)); 1310 if (!has) { 1311 if (defaultValue) { 1312 if (defaultValue != value) { 1313 if (datatype == PETSC_STRING) { 1314 PetscCall(PetscStrallocpy(*(char **)defaultValue, (char **)value)); 1315 } else { 1316 size_t len; 1317 PetscCallHDF5ReturnNoCheck(len, H5Tget_size, (dtype)); 1318 PetscCall(PetscMemcpy(value, defaultValue, len)); 1319 } 1320 } 1321 PetscCall(PetscFree(parentAbsPath)); 1322 PetscFunctionReturn(PETSC_SUCCESS); 1323 } else SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Attribute %s/%s does not exist and default value not provided", parentAbsPath, name); 1324 } 1325 PetscCall(PetscViewerHDF5GetFileId(viewer, &h5)); 1326 PetscCallHDF5Return(obj, H5Oopen, (h5, parentAbsPath, H5P_DEFAULT)); 1327 PetscCallHDF5Return(attribute, H5Aopen_name, (obj, name)); 1328 if (datatype == PETSC_STRING) { 1329 size_t len; 1330 hid_t atype; 1331 PetscCallHDF5Return(atype, H5Aget_type, (attribute)); 1332 PetscCallHDF5ReturnNoCheck(len, H5Tget_size, (atype)); 1333 PetscCall(PetscMalloc((len + 1) * sizeof(char), value)); 1334 PetscCallHDF5(H5Tset_size, (dtype, len + 1)); 1335 PetscCallHDF5(H5Aread, (attribute, dtype, *(char **)value)); 1336 } else { 1337 PetscCallHDF5(H5Aread, (attribute, dtype, value)); 1338 } 1339 PetscCallHDF5(H5Aclose, (attribute)); 1340 /* H5Oclose can be used to close groups, datasets, or committed datatypes */ 1341 PetscCallHDF5(H5Oclose, (obj)); 1342 PetscCall(PetscFree(parentAbsPath)); 1343 PetscFunctionReturn(PETSC_SUCCESS); 1344 } 1345 1346 /*@C 1347 PetscViewerHDF5ReadObjectAttribute - Read an attribute from the dataset matching the given `PetscObject` by name 1348 1349 Collective 1350 1351 Input Parameters: 1352 + viewer - The `PETSCVIEWERHDF5` viewer 1353 . obj - The object whose name is used to lookup the parent dataset, relative to the current group. 1354 . name - The attribute name 1355 . datatype - The attribute type 1356 - defaultValue - The default attribute value 1357 1358 Output Parameter: 1359 . value - The attribute value 1360 1361 Level: advanced 1362 1363 Note: 1364 This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset). 1365 You might want to check first if it does using `PetscViewerHDF5HasObject()`. 1366 1367 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5ReadAttribute()` `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5HasObjectAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1368 @*/ 1369 PetscErrorCode PetscViewerHDF5ReadObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscDataType datatype, void *defaultValue, void *value) 1370 { 1371 PetscFunctionBegin; 1372 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1373 PetscValidHeader(obj, 2); 1374 PetscAssertPointer(name, 3); 1375 PetscAssertPointer(value, 6); 1376 PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj)); 1377 PetscCall(PetscViewerHDF5ReadAttribute(viewer, obj->name, name, datatype, defaultValue, value)); 1378 PetscFunctionReturn(PETSC_SUCCESS); 1379 } 1380 1381 static PetscErrorCode PetscViewerHDF5Traverse_Inner_Internal(hid_t h5, const char name[], PetscBool createGroup, PetscBool *exists_) 1382 { 1383 htri_t exists; 1384 hid_t group; 1385 1386 PetscFunctionBegin; 1387 PetscCallHDF5Return(exists, H5Lexists, (h5, name, H5P_DEFAULT)); 1388 if (exists) PetscCallHDF5Return(exists, H5Oexists_by_name, (h5, name, H5P_DEFAULT)); 1389 if (!exists && createGroup) { 1390 PetscCallHDF5Return(group, H5Gcreate2, (h5, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)); 1391 PetscCallHDF5(H5Gclose, (group)); 1392 exists = PETSC_TRUE; 1393 } 1394 *exists_ = (PetscBool)exists; 1395 PetscFunctionReturn(PETSC_SUCCESS); 1396 } 1397 1398 static PetscErrorCode PetscViewerHDF5Traverse_Internal(PetscViewer viewer, const char name[], PetscBool createGroup, PetscBool *has, H5O_type_t *otype) 1399 { 1400 const char rootGroupName[] = "/"; 1401 hid_t h5; 1402 PetscBool exists = PETSC_FALSE; 1403 PetscInt i; 1404 int n; 1405 char **hierarchy; 1406 char buf[PETSC_MAX_PATH_LEN] = ""; 1407 1408 PetscFunctionBegin; 1409 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1410 if (name) PetscAssertPointer(name, 2); 1411 else name = rootGroupName; 1412 if (has) { 1413 PetscAssertPointer(has, 4); 1414 *has = PETSC_FALSE; 1415 } 1416 if (otype) { 1417 PetscAssertPointer(otype, 5); 1418 *otype = H5O_TYPE_UNKNOWN; 1419 } 1420 PetscCall(PetscViewerHDF5GetFileId(viewer, &h5)); 1421 1422 /* 1423 Unfortunately, H5Oexists_by_name() fails if any object in hierarchy is missing. 1424 Hence, each of them needs to be tested separately: 1425 1) whether it's a valid link 1426 2) whether this link resolves to an object 1427 See H5Oexists_by_name() documentation. 1428 */ 1429 PetscCall(PetscStrToArray(name, '/', &n, &hierarchy)); 1430 if (!n) { 1431 /* Assume group "/" always exists in accordance with HDF5 >= 1.10.0. See H5Lexists() documentation. */ 1432 if (has) *has = PETSC_TRUE; 1433 if (otype) *otype = H5O_TYPE_GROUP; 1434 PetscCall(PetscStrToArrayDestroy(n, hierarchy)); 1435 PetscFunctionReturn(PETSC_SUCCESS); 1436 } 1437 for (i = 0; i < n; i++) { 1438 PetscCall(PetscStrlcat(buf, "/", sizeof(buf))); 1439 PetscCall(PetscStrlcat(buf, hierarchy[i], sizeof(buf))); 1440 PetscCall(PetscViewerHDF5Traverse_Inner_Internal(h5, buf, createGroup, &exists)); 1441 if (!exists) break; 1442 } 1443 PetscCall(PetscStrToArrayDestroy(n, hierarchy)); 1444 1445 /* If the object exists, get its type */ 1446 if (exists && otype) { 1447 H5O_info_t info; 1448 1449 /* We could use H5Iget_type() here but that would require opening the object. This way we only need its name. */ 1450 PetscCallHDF5(H5Oget_info_by_name, (h5, name, &info, H5P_DEFAULT)); 1451 *otype = info.type; 1452 } 1453 if (has) *has = exists; 1454 PetscFunctionReturn(PETSC_SUCCESS); 1455 } 1456 1457 /*@C 1458 PetscViewerHDF5HasGroup - Check whether the current (pushed) group exists in the HDF5 file 1459 1460 Collective 1461 1462 Input Parameters: 1463 + viewer - The `PETSCVIEWERHDF5` viewer 1464 - path - (Optional) The path relative to the pushed group 1465 1466 Output Parameter: 1467 . has - Flag for group existence 1468 1469 Level: advanced 1470 1471 Notes: 1472 If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group. 1473 `NULL` or empty path means the current pushed group. 1474 1475 If path exists but is not a group, `PETSC_FALSE` is returned. 1476 1477 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasDataset()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()`, `PetscViewerHDF5OpenGroup()` 1478 @*/ 1479 PetscErrorCode PetscViewerHDF5HasGroup(PetscViewer viewer, const char path[], PetscBool *has) 1480 { 1481 H5O_type_t type; 1482 const char *abspath; 1483 1484 PetscFunctionBegin; 1485 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1486 if (path) PetscAssertPointer(path, 2); 1487 PetscAssertPointer(has, 3); 1488 PetscCall(PetscViewerHDF5GetGroup(viewer, path, &abspath)); 1489 PetscCall(PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type)); 1490 *has = (PetscBool)(type == H5O_TYPE_GROUP); 1491 PetscCall(PetscFree(abspath)); 1492 PetscFunctionReturn(PETSC_SUCCESS); 1493 } 1494 1495 /*@C 1496 PetscViewerHDF5HasDataset - Check whether a given dataset exists in the HDF5 file 1497 1498 Collective 1499 1500 Input Parameters: 1501 + viewer - The `PETSCVIEWERHDF5` viewer 1502 - path - The dataset path 1503 1504 Output Parameter: 1505 . has - Flag whether dataset exists 1506 1507 Level: advanced 1508 1509 Notes: 1510 If path starts with '/', it is taken as an absolute path overriding currently pushed group, else path is relative to the current pushed group. 1511 1512 If `path` is `NULL` or empty, has is set to `PETSC_FALSE`. 1513 1514 If `path` exists but is not a dataset, has is set to `PETSC_FALSE` as well. 1515 1516 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5HasGroup()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1517 @*/ 1518 PetscErrorCode PetscViewerHDF5HasDataset(PetscViewer viewer, const char path[], PetscBool *has) 1519 { 1520 H5O_type_t type; 1521 const char *abspath; 1522 1523 PetscFunctionBegin; 1524 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1525 if (path) PetscAssertPointer(path, 2); 1526 PetscAssertPointer(has, 3); 1527 PetscCall(PetscViewerHDF5GetGroup(viewer, path, &abspath)); 1528 PetscCall(PetscViewerHDF5Traverse_Internal(viewer, abspath, PETSC_FALSE, NULL, &type)); 1529 *has = (PetscBool)(type == H5O_TYPE_DATASET); 1530 PetscCall(PetscFree(abspath)); 1531 PetscFunctionReturn(PETSC_SUCCESS); 1532 } 1533 1534 /*@ 1535 PetscViewerHDF5HasObject - Check whether a dataset with the same name as given object exists in the HDF5 file under current group 1536 1537 Collective 1538 1539 Input Parameters: 1540 + viewer - The `PETSCVIEWERHDF5` viewer 1541 - obj - The named object 1542 1543 Output Parameter: 1544 . has - Flag for dataset existence 1545 1546 Level: advanced 1547 1548 Notes: 1549 If the object is unnamed, an error occurs. 1550 1551 If the path current_group/object_name exists but is not a dataset, has is set to `PETSC_FALSE` as well. 1552 1553 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasDataset()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1554 @*/ 1555 PetscErrorCode PetscViewerHDF5HasObject(PetscViewer viewer, PetscObject obj, PetscBool *has) 1556 { 1557 size_t len; 1558 1559 PetscFunctionBegin; 1560 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1561 PetscValidHeader(obj, 2); 1562 PetscAssertPointer(has, 3); 1563 PetscCall(PetscStrlen(obj->name, &len)); 1564 PetscCheck(len, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Object must be named"); 1565 PetscCall(PetscViewerHDF5HasDataset(viewer, obj->name, has)); 1566 PetscFunctionReturn(PETSC_SUCCESS); 1567 } 1568 1569 /*@C 1570 PetscViewerHDF5HasAttribute - Check whether an attribute exists 1571 1572 Collective 1573 1574 Input Parameters: 1575 + viewer - The `PETSCVIEWERHDF5` viewer 1576 . parent - The parent dataset/group name 1577 - name - The attribute name 1578 1579 Output Parameter: 1580 . has - Flag for attribute existence 1581 1582 Level: advanced 1583 1584 Note: 1585 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. 1586 1587 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasObjectAttribute()`, `PetscViewerHDF5WriteAttribute()`, `PetscViewerHDF5ReadAttribute()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1588 @*/ 1589 PetscErrorCode PetscViewerHDF5HasAttribute(PetscViewer viewer, const char parent[], const char name[], PetscBool *has) 1590 { 1591 const char *parentAbsPath; 1592 1593 PetscFunctionBegin; 1594 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1595 if (parent) PetscAssertPointer(parent, 2); 1596 PetscAssertPointer(name, 3); 1597 PetscAssertPointer(has, 4); 1598 PetscCall(PetscViewerHDF5GetGroup(viewer, parent, &parentAbsPath)); 1599 PetscCall(PetscViewerHDF5Traverse_Internal(viewer, parentAbsPath, PETSC_FALSE, has, NULL)); 1600 if (*has) PetscCall(PetscViewerHDF5HasAttribute_Internal(viewer, parentAbsPath, name, has)); 1601 PetscCall(PetscFree(parentAbsPath)); 1602 PetscFunctionReturn(PETSC_SUCCESS); 1603 } 1604 1605 /*@C 1606 PetscViewerHDF5HasObjectAttribute - Check whether an attribute is attached to the dataset matching the given `PetscObject` by name 1607 1608 Collective 1609 1610 Input Parameters: 1611 + viewer - The `PETSCVIEWERHDF5` viewer 1612 . obj - The object whose name is used to lookup the parent dataset, relative to the current group. 1613 - name - The attribute name 1614 1615 Output Parameter: 1616 . has - Flag for attribute existence 1617 1618 Level: advanced 1619 1620 Note: 1621 This fails if current_group/object_name doesn't resolve to a dataset (the path doesn't exist or is not a dataset). 1622 You might want to check first if it does using `PetscViewerHDF5HasObject()`. 1623 1624 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerHDF5HasAttribute()`, `PetscViewerHDF5WriteObjectAttribute()`, `PetscViewerHDF5ReadObjectAttribute()`, `PetscViewerHDF5HasObject()`, `PetscViewerHDF5PushGroup()`, `PetscViewerHDF5PopGroup()`, `PetscViewerHDF5GetGroup()` 1625 @*/ 1626 PetscErrorCode PetscViewerHDF5HasObjectAttribute(PetscViewer viewer, PetscObject obj, const char name[], PetscBool *has) 1627 { 1628 PetscFunctionBegin; 1629 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1630 PetscValidHeader(obj, 2); 1631 PetscAssertPointer(name, 3); 1632 PetscAssertPointer(has, 4); 1633 PetscCall(PetscViewerHDF5CheckNamedObject_Internal(viewer, obj)); 1634 PetscCall(PetscViewerHDF5HasAttribute(viewer, obj->name, name, has)); 1635 PetscFunctionReturn(PETSC_SUCCESS); 1636 } 1637 1638 static PetscErrorCode PetscViewerHDF5HasAttribute_Internal(PetscViewer viewer, const char parent[], const char name[], PetscBool *has) 1639 { 1640 hid_t h5; 1641 htri_t hhas; 1642 1643 PetscFunctionBegin; 1644 PetscCall(PetscViewerHDF5GetFileId(viewer, &h5)); 1645 PetscCallHDF5Return(hhas, H5Aexists_by_name, (h5, parent, name, H5P_DEFAULT)); 1646 *has = hhas ? PETSC_TRUE : PETSC_FALSE; 1647 PetscFunctionReturn(PETSC_SUCCESS); 1648 } 1649 1650 /* 1651 The variable Petsc_Viewer_HDF5_keyval is used to indicate an MPI attribute that 1652 is attached to a communicator, in this case the attribute is a PetscViewer. 1653 */ 1654 PetscMPIInt Petsc_Viewer_HDF5_keyval = MPI_KEYVAL_INVALID; 1655 1656 /*@C 1657 PETSC_VIEWER_HDF5_ - Creates an `PETSCVIEWERHDF5` `PetscViewer` shared by all processors in a communicator. 1658 1659 Collective 1660 1661 Input Parameter: 1662 . comm - the MPI communicator to share the `PETSCVIEWERHDF5` `PetscViewer` 1663 1664 Options Database Key: 1665 . -viewer_hdf5_filename <name> - name of the HDF5 file 1666 1667 Environmental variable: 1668 . `PETSC_VIEWER_HDF5_FILENAME` - name of the HDF5 file 1669 1670 Level: intermediate 1671 1672 Note: 1673 Unlike almost all other PETSc routines, `PETSC_VIEWER_HDF5_()` does not return 1674 an error code. The HDF5 `PetscViewer` is usually used in the form 1675 .vb 1676 XXXView(XXX object, PETSC_VIEWER_HDF5_(comm)); 1677 .ve 1678 1679 .seealso: [](sec_viewers), `PETSCVIEWERHDF5`, `PetscViewerHDF5Open()`, `PetscViewerCreate()`, `PetscViewerDestroy()` 1680 @*/ 1681 PetscViewer PETSC_VIEWER_HDF5_(MPI_Comm comm) 1682 { 1683 PetscErrorCode ierr; 1684 PetscMPIInt mpi_ierr; 1685 PetscBool flg; 1686 PetscViewer viewer; 1687 char fname[PETSC_MAX_PATH_LEN]; 1688 MPI_Comm ncomm; 1689 1690 PetscFunctionBegin; 1691 ierr = PetscCommDuplicate(comm, &ncomm, NULL); 1692 if (ierr) { 1693 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1694 PetscFunctionReturn(NULL); 1695 } 1696 if (Petsc_Viewer_HDF5_keyval == MPI_KEYVAL_INVALID) { 1697 mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_HDF5_keyval, NULL); 1698 if (mpi_ierr) { 1699 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1700 PetscFunctionReturn(NULL); 1701 } 1702 } 1703 mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_HDF5_keyval, (void **)&viewer, (int *)&flg); 1704 if (mpi_ierr) { 1705 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1706 PetscFunctionReturn(NULL); 1707 } 1708 if (!flg) { /* PetscViewer not yet created */ 1709 ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_HDF5_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg); 1710 if (ierr) { 1711 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1712 PetscFunctionReturn(NULL); 1713 } 1714 if (!flg) { 1715 ierr = PetscStrncpy(fname, "output.h5", sizeof(fname)); 1716 if (ierr) { 1717 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1718 PetscFunctionReturn(NULL); 1719 } 1720 } 1721 ierr = PetscViewerHDF5Open(ncomm, fname, FILE_MODE_WRITE, &viewer); 1722 if (ierr) { 1723 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1724 PetscFunctionReturn(NULL); 1725 } 1726 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 1727 if (ierr) { 1728 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1729 PetscFunctionReturn(NULL); 1730 } 1731 mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_HDF5_keyval, (void *)viewer); 1732 if (mpi_ierr) { 1733 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1734 PetscFunctionReturn(NULL); 1735 } 1736 } 1737 ierr = PetscCommDestroy(&ncomm); 1738 if (ierr) { 1739 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_HDF5_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1740 PetscFunctionReturn(NULL); 1741 } 1742 PetscFunctionReturn(viewer); 1743 } 1744