1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/viewerhdf5impl.h> 5 #include <petsclayouthdf5.h> 6 7 static PetscErrorCode PetscViewerParseVersion_Private(PetscViewer, const char[], DMPlexStorageVersion *); 8 static PetscErrorCode PetscViewerCheckVersion_Private(PetscViewer, DMPlexStorageVersion); 9 static PetscErrorCode PetscViewerAttachVersion_Private(PetscViewer, const char[], DMPlexStorageVersion); 10 static PetscErrorCode PetscViewerGetAttachedVersion_Private(PetscViewer, const char[], DMPlexStorageVersion *); 11 12 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 13 14 static PetscErrorCode PetscViewerPrintVersion_Private(PetscViewer viewer, DMPlexStorageVersion version, char str[], size_t len) 15 { 16 PetscFunctionBegin; 17 PetscCall(PetscViewerCheckVersion_Private(viewer, version)); 18 PetscCall(PetscSNPrintf(str, len, "%d.%d.%d", version->major, version->minor, version->subminor)); 19 PetscFunctionReturn(PETSC_SUCCESS); 20 } 21 22 static PetscErrorCode PetscViewerParseVersion_Private(PetscViewer viewer, const char str[], DMPlexStorageVersion *version) 23 { 24 PetscToken t; 25 const char *ts; 26 PetscInt i; 27 PetscInt ti[3]; 28 DMPlexStorageVersion v; 29 30 PetscFunctionBegin; 31 PetscCall(PetscTokenCreate(str, '.', &t)); 32 for (i = 0; i < 3; i++) { 33 PetscCall(PetscTokenFind(t, &ts)); 34 PetscCheck(ts, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Malformed version string %s", str); 35 PetscCall(PetscOptionsStringToInt(ts, &ti[i])); 36 } 37 PetscCall(PetscTokenFind(t, &ts)); 38 PetscCheck(!ts, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONG, "Malformed version string %s", str); 39 PetscCall(PetscTokenDestroy(&t)); 40 PetscCall(PetscNew(&v)); 41 v->major = (int)ti[0]; 42 v->minor = (int)ti[1]; 43 v->subminor = (int)ti[2]; 44 PetscCall(PetscViewerCheckVersion_Private(viewer, v)); 45 *version = v; 46 PetscFunctionReturn(PETSC_SUCCESS); 47 } 48 49 static PetscErrorCode PetscViewerAttachVersion_Private(PetscViewer viewer, const char key[], DMPlexStorageVersion v) 50 { 51 PetscFunctionBegin; 52 PetscCall(PetscObjectContainerCompose((PetscObject)viewer, key, v, PetscCtxDestroyDefault)); 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 static PetscErrorCode PetscViewerGetAttachedVersion_Private(PetscViewer viewer, const char key[], DMPlexStorageVersion *v) 57 { 58 PetscContainer cont; 59 60 PetscFunctionBegin; 61 PetscCall(PetscObjectQuery((PetscObject)viewer, key, (PetscObject *)&cont)); 62 *v = NULL; 63 if (cont) PetscCall(PetscContainerGetPointer(cont, (void **)v)); 64 PetscFunctionReturn(PETSC_SUCCESS); 65 } 66 67 /* 68 Version log: 69 1.0.0 legacy version (default if no "dmplex_storage_version" attribute found in file) 70 1.1.0 legacy version, but output VIZ by default 71 2.0.0 introduce versioning and multiple topologies 72 2.1.0 introduce distributions 73 3.0.0 new checkpointing format in Firedrake paper 74 3.1.0 new format with IS compression 75 */ 76 static PetscErrorCode PetscViewerCheckVersion_Private(PetscViewer viewer, DMPlexStorageVersion version) 77 { 78 PetscBool valid = PETSC_FALSE; 79 80 PetscFunctionBegin; 81 switch (version->major) { 82 case 1: 83 switch (version->minor) { 84 case 0: 85 switch (version->subminor) { 86 case 0: 87 valid = PETSC_TRUE; 88 break; 89 } 90 break; 91 case 1: 92 switch (version->subminor) { 93 case 0: 94 valid = PETSC_TRUE; 95 break; 96 } 97 break; 98 } 99 break; 100 case 2: 101 switch (version->minor) { 102 case 0: 103 switch (version->subminor) { 104 case 0: 105 valid = PETSC_TRUE; 106 break; 107 } 108 break; 109 case 1: 110 switch (version->subminor) { 111 case 0: 112 valid = PETSC_TRUE; 113 break; 114 } 115 break; 116 } 117 break; 118 case 3: 119 switch (version->minor) { 120 case 0: 121 switch (version->subminor) { 122 case 0: 123 valid = PETSC_TRUE; 124 break; 125 } 126 break; 127 case 1: 128 switch (version->subminor) { 129 case 0: 130 valid = PETSC_TRUE; 131 break; 132 } 133 break; 134 } 135 break; 136 } 137 PetscCheck(valid, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "DMPlexStorageVersion %d.%d.%d not supported", version->major, version->minor, version->subminor); 138 PetscFunctionReturn(PETSC_SUCCESS); 139 } 140 141 static inline PetscBool DMPlexStorageVersionEQ(DMPlexStorageVersion version, int major, int minor, int subminor) 142 { 143 return (PetscBool)(version->major == major && version->minor == minor && version->subminor == subminor); 144 } 145 146 static inline PetscBool DMPlexStorageVersionGE(DMPlexStorageVersion version, int major, int minor, int subminor) 147 { 148 return (PetscBool)((version->major == major && version->minor == minor && version->subminor >= subminor) || (version->major == major && version->minor > minor) || (version->major > major)); 149 } 150 151 /*@C 152 PetscViewerHDF5SetDMPlexStorageVersionWriting - Set the storage version for writing 153 154 Logically collective 155 156 Input Parameters: 157 + viewer - The `PetscViewer` 158 - version - The storage format version 159 160 Level: advanced 161 162 Note: 163 The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0. 164 165 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()` 166 @*/ 167 PetscErrorCode PetscViewerHDF5SetDMPlexStorageVersionWriting(PetscViewer viewer, DMPlexStorageVersion version) 168 { 169 const char ATTR_NAME[] = "dmplex_storage_version"; 170 DMPlexStorageVersion viewerVersion; 171 PetscBool fileHasVersion; 172 char fileVersion[16], versionStr[16], viewerVersionStr[16]; 173 174 PetscFunctionBegin; 175 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5); 176 PetscAssertPointer(version, 2); 177 PetscCall(PetscViewerPrintVersion_Private(viewer, version, versionStr, 16)); 178 PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, &viewerVersion)); 179 if (viewerVersion) { 180 PetscBool flg; 181 182 PetscCall(PetscViewerPrintVersion_Private(viewer, viewerVersion, viewerVersionStr, 16)); 183 PetscCall(PetscStrcmp(versionStr, viewerVersionStr, &flg)); 184 PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but viewer already has version %s - cannot mix versions", versionStr, viewerVersionStr); 185 } 186 187 PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion)); 188 if (fileHasVersion) { 189 PetscBool flg; 190 char *tmp; 191 192 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &tmp)); 193 PetscCall(PetscStrncpy(fileVersion, tmp, sizeof(fileVersion))); 194 PetscCall(PetscFree(tmp)); 195 PetscCall(PetscStrcmp(fileVersion, versionStr, &flg)); 196 PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", versionStr, fileVersion); 197 } else { 198 PetscCall(PetscViewerHDF5WriteAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, versionStr)); 199 } 200 PetscCall(PetscNew(&viewerVersion)); 201 viewerVersion->major = version->major; 202 viewerVersion->minor = version->minor; 203 viewerVersion->subminor = version->subminor; 204 PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, viewerVersion)); 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 /*@C 209 PetscViewerHDF5GetDMPlexStorageVersionWriting - Get the storage version for writing 210 211 Logically collective 212 213 Input Parameter: 214 . viewer - The `PetscViewer` 215 216 Output Parameter: 217 . version - The storage format version 218 219 Options Database Keys: 220 . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version 221 222 Level: advanced 223 224 Note: 225 The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0. 226 227 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5SetDMPlexStorageVersionReading()` 228 @*/ 229 PetscErrorCode PetscViewerHDF5GetDMPlexStorageVersionWriting(PetscViewer viewer, DMPlexStorageVersion *version) 230 { 231 const char ATTR_NAME[] = "dmplex_storage_version"; 232 PetscBool fileHasVersion; 233 char optVersion[16], fileVersion[16]; 234 235 PetscFunctionBegin; 236 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5); 237 PetscAssertPointer(version, 2); 238 PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, version)); 239 if (*version) PetscFunctionReturn(PETSC_SUCCESS); 240 241 PetscCall(PetscStrncpy(fileVersion, DMPLEX_STORAGE_VERSION_STABLE, sizeof(fileVersion))); 242 PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion)); 243 if (fileHasVersion) { 244 char *tmp; 245 246 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &tmp)); 247 PetscCall(PetscStrncpy(fileVersion, tmp, sizeof(fileVersion))); 248 PetscCall(PetscFree(tmp)); 249 } 250 PetscCall(PetscStrncpy(optVersion, fileVersion, sizeof(optVersion))); 251 PetscObjectOptionsBegin((PetscObject)viewer); 252 PetscCall(PetscOptionsString("-dm_plex_view_hdf5_storage_version", "DMPlex HDF5 viewer storage version", NULL, optVersion, optVersion, sizeof(optVersion), NULL)); 253 PetscOptionsEnd(); 254 if (!fileHasVersion) { 255 PetscCall(PetscViewerHDF5WriteAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, optVersion)); 256 } else { 257 PetscBool flg; 258 259 PetscCall(PetscStrcmp(fileVersion, optVersion, &flg)); 260 PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", optVersion, fileVersion); 261 } 262 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "petsc_version_git", PETSC_STRING, PETSC_VERSION_GIT)); 263 PetscCall(PetscViewerParseVersion_Private(viewer, optVersion, version)); 264 PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_WRITING_KEY, *version)); 265 PetscFunctionReturn(PETSC_SUCCESS); 266 } 267 268 /*@C 269 PetscViewerHDF5SetDMPlexStorageVersionReading - Set the storage version for reading 270 271 Logically collective 272 273 Input Parameters: 274 + viewer - The `PetscViewer` 275 - version - The storage format version 276 277 Level: advanced 278 279 Note: 280 The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0. 281 282 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5GetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()` 283 @*/ 284 PetscErrorCode PetscViewerHDF5SetDMPlexStorageVersionReading(PetscViewer viewer, DMPlexStorageVersion version) 285 { 286 const char ATTR_NAME[] = "dmplex_storage_version"; 287 DMPlexStorageVersion viewerVersion; 288 PetscBool fileHasVersion; 289 char versionStr[16], viewerVersionStr[16]; 290 291 PetscFunctionBegin; 292 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5); 293 PetscAssertPointer(version, 2); 294 PetscCall(PetscViewerPrintVersion_Private(viewer, version, versionStr, 16)); 295 PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, &viewerVersion)); 296 if (viewerVersion) { 297 PetscBool flg; 298 299 PetscCall(PetscViewerPrintVersion_Private(viewer, viewerVersion, viewerVersionStr, 16)); 300 PetscCall(PetscStrcmp(versionStr, viewerVersionStr, &flg)); 301 PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but viewer already has version %s - cannot mix versions", versionStr, viewerVersionStr); 302 } 303 304 PetscCall(PetscViewerHDF5HasAttribute(viewer, NULL, ATTR_NAME, &fileHasVersion)); 305 if (fileHasVersion) { 306 char *fileVersion; 307 PetscBool flg; 308 309 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, NULL, &fileVersion)); 310 PetscCall(PetscStrcmp(fileVersion, versionStr, &flg)); 311 PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "User requested DMPlex storage version %s but file already has version %s - cannot mix versions", versionStr, fileVersion); 312 PetscCall(PetscFree(fileVersion)); 313 } 314 PetscCall(PetscNew(&viewerVersion)); 315 viewerVersion->major = version->major; 316 viewerVersion->minor = version->minor; 317 viewerVersion->subminor = version->subminor; 318 PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, viewerVersion)); 319 PetscFunctionReturn(PETSC_SUCCESS); 320 } 321 322 /*@C 323 PetscViewerHDF5GetDMPlexStorageVersionReading - Get the storage version for reading 324 325 Logically collective 326 327 Input Parameter: 328 . viewer - The `PetscViewer` 329 330 Output Parameter: 331 . version - The storage format version 332 333 Options Database Keys: 334 . -dm_plex_view_hdf5_storage_version <num> - Overrides the storage format version 335 336 Level: advanced 337 338 Note: 339 The version has major, minor, and subminor integers. Parallel operations are only available for version 3.0.0. 340 341 .seealso: [](ch_dmbase), `DM`, `PetscViewerHDF5SetDMPlexStorageVersionReading()`, `PetscViewerHDF5GetDMPlexStorageVersionWriting()`, `PetscViewerHDF5SetDMPlexStorageVersionWriting()` 342 @*/ 343 PetscErrorCode PetscViewerHDF5GetDMPlexStorageVersionReading(PetscViewer viewer, DMPlexStorageVersion *version) 344 { 345 const char ATTR_NAME[] = "dmplex_storage_version"; 346 char *defaultVersion; 347 char *versionString; 348 349 PetscFunctionBegin; 350 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERHDF5); 351 PetscAssertPointer(version, 2); 352 PetscCall(PetscViewerGetAttachedVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, version)); 353 if (*version) PetscFunctionReturn(PETSC_SUCCESS); 354 355 //TODO string HDF5 attribute handling is terrible and should be redesigned 356 PetscCall(PetscStrallocpy(DMPLEX_STORAGE_VERSION_FIRST, &defaultVersion)); 357 PetscCall(PetscViewerHDF5ReadAttribute(viewer, "/", ATTR_NAME, PETSC_STRING, &defaultVersion, &versionString)); 358 PetscCall(PetscViewerParseVersion_Private(viewer, versionString, version)); 359 PetscCall(PetscViewerAttachVersion_Private(viewer, DMPLEX_STORAGE_VERSION_READING_KEY, *version)); 360 PetscCall(PetscFree(versionString)); 361 PetscCall(PetscFree(defaultVersion)); 362 PetscFunctionReturn(PETSC_SUCCESS); 363 } 364 365 static PetscErrorCode DMPlexGetHDF5Name_Private(DM dm, const char *name[]) 366 { 367 PetscFunctionBegin; 368 if (((PetscObject)dm)->name) { 369 PetscCall(PetscObjectGetName((PetscObject)dm, name)); 370 } else { 371 *name = "plex"; 372 } 373 PetscFunctionReturn(PETSC_SUCCESS); 374 } 375 376 PetscErrorCode DMSequenceGetLength_HDF5_Internal(DM dm, const char seqname[], PetscInt *seqlen, PetscViewer viewer) 377 { 378 hid_t file, group, dset, dspace; 379 hsize_t rdim, *dims; 380 const char *groupname; 381 PetscBool has; 382 383 PetscFunctionBegin; 384 PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &groupname)); 385 PetscCall(PetscViewerHDF5HasDataset(viewer, seqname, &has)); 386 PetscCheck(has, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Object (dataset) \"%s\" not stored in group %s", seqname, groupname); 387 388 PetscCall(PetscViewerHDF5OpenGroup(viewer, NULL, &file, &group)); 389 PetscCallHDF5Return(dset, H5Dopen2, (group, seqname, H5P_DEFAULT)); 390 PetscCallHDF5Return(dspace, H5Dget_space, (dset)); 391 PetscCallHDF5ReturnNoCheck(rdim, H5Sget_simple_extent_dims, (dspace, NULL, NULL)); 392 PetscCall(PetscMalloc1(rdim, &dims)); 393 PetscCallHDF5ReturnNoCheck(rdim, H5Sget_simple_extent_dims, (dspace, dims, NULL)); 394 *seqlen = (PetscInt)dims[0]; 395 PetscCall(PetscFree(dims)); 396 PetscCallHDF5(H5Dclose, (dset)); 397 PetscCallHDF5(H5Gclose, (group)); 398 PetscFunctionReturn(PETSC_SUCCESS); 399 } 400 401 static PetscErrorCode DMSequenceView_HDF5(DM dm, const char seqname[], PetscInt seqnum, PetscScalar value, PetscViewer viewer) 402 { 403 Vec stamp; 404 PetscMPIInt rank; 405 406 PetscFunctionBegin; 407 if (seqnum < 0) PetscFunctionReturn(PETSC_SUCCESS); 408 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 409 PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)viewer), rank ? 0 : 1, 1, &stamp)); 410 PetscCall(VecSetBlockSize(stamp, 1)); 411 PetscCall(PetscObjectSetName((PetscObject)stamp, seqname)); 412 if (rank == 0) { 413 PetscReal timeScale; 414 PetscBool istime; 415 416 PetscCall(PetscStrncmp(seqname, "time", 5, &istime)); 417 if (istime) { 418 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_TIME, &timeScale)); 419 value *= timeScale; 420 } 421 PetscCall(VecSetValue(stamp, 0, value, INSERT_VALUES)); 422 } 423 PetscCall(VecAssemblyBegin(stamp)); 424 PetscCall(VecAssemblyEnd(stamp)); 425 PetscCall(PetscViewerHDF5PushGroup(viewer, "/")); 426 PetscCall(PetscViewerHDF5PushTimestepping(viewer)); 427 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); /* seqnum < 0 jumps out above */ 428 PetscCall(VecView(stamp, viewer)); 429 PetscCall(PetscViewerHDF5PopTimestepping(viewer)); 430 PetscCall(PetscViewerHDF5PopGroup(viewer)); 431 PetscCall(VecDestroy(&stamp)); 432 PetscFunctionReturn(PETSC_SUCCESS); 433 } 434 435 PetscErrorCode DMSequenceLoad_HDF5_Internal(DM dm, const char seqname[], PetscInt seqnum, PetscScalar *value, PetscViewer viewer) 436 { 437 Vec stamp; 438 PetscMPIInt rank; 439 440 PetscFunctionBegin; 441 if (seqnum < 0) PetscFunctionReturn(PETSC_SUCCESS); 442 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 443 PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)viewer), rank ? 0 : 1, 1, &stamp)); 444 PetscCall(VecSetBlockSize(stamp, 1)); 445 PetscCall(PetscObjectSetName((PetscObject)stamp, seqname)); 446 PetscCall(PetscViewerHDF5PushGroup(viewer, "/")); 447 PetscCall(PetscViewerHDF5PushTimestepping(viewer)); 448 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); /* seqnum < 0 jumps out above */ 449 PetscCall(VecLoad(stamp, viewer)); 450 PetscCall(PetscViewerHDF5PopTimestepping(viewer)); 451 PetscCall(PetscViewerHDF5PopGroup(viewer)); 452 if (rank == 0) { 453 const PetscScalar *a; 454 PetscReal timeScale; 455 PetscBool istime; 456 457 PetscCall(VecGetArrayRead(stamp, &a)); 458 *value = a[0]; 459 PetscCall(VecRestoreArrayRead(stamp, &a)); 460 PetscCall(PetscStrncmp(seqname, "time", 5, &istime)); 461 if (istime) { 462 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_TIME, &timeScale)); 463 *value /= timeScale; 464 } 465 } 466 PetscCall(VecDestroy(&stamp)); 467 PetscFunctionReturn(PETSC_SUCCESS); 468 } 469 470 static PetscErrorCode DMPlexCreateCutVertexLabel_Private(DM dm, DMLabel cutLabel, DMLabel *cutVertexLabel) 471 { 472 IS cutcells = NULL; 473 const PetscInt *cutc; 474 PetscInt cellHeight, vStart, vEnd, cStart, cEnd, c; 475 476 PetscFunctionBegin; 477 if (!cutLabel) PetscFunctionReturn(PETSC_SUCCESS); 478 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 479 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 480 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 481 /* Label vertices that should be duplicated */ 482 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Cut Vertices", cutVertexLabel)); 483 PetscCall(DMLabelGetStratumIS(cutLabel, 2, &cutcells)); 484 if (cutcells) { 485 PetscInt n; 486 487 PetscCall(ISGetIndices(cutcells, &cutc)); 488 PetscCall(ISGetLocalSize(cutcells, &n)); 489 for (c = 0; c < n; ++c) { 490 if ((cutc[c] >= cStart) && (cutc[c] < cEnd)) { 491 PetscInt *closure = NULL; 492 PetscInt closureSize, cl, value; 493 494 PetscCall(DMPlexGetTransitiveClosure(dm, cutc[c], PETSC_TRUE, &closureSize, &closure)); 495 for (cl = 0; cl < closureSize * 2; cl += 2) { 496 if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) { 497 PetscCall(DMLabelGetValue(cutLabel, closure[cl], &value)); 498 if (value == 1) PetscCall(DMLabelSetValue(*cutVertexLabel, closure[cl], 1)); 499 } 500 } 501 PetscCall(DMPlexRestoreTransitiveClosure(dm, cutc[c], PETSC_TRUE, &closureSize, &closure)); 502 } 503 } 504 PetscCall(ISRestoreIndices(cutcells, &cutc)); 505 } 506 PetscCall(ISDestroy(&cutcells)); 507 PetscFunctionReturn(PETSC_SUCCESS); 508 } 509 510 PetscErrorCode VecView_Plex_Local_HDF5_Internal(Vec v, PetscViewer viewer) 511 { 512 DMPlexStorageVersion version; 513 DM dm; 514 DM dmBC; 515 PetscSection section, sectionGlobal; 516 Vec gv; 517 const char *name; 518 PetscViewerFormat format; 519 PetscInt seqnum; 520 PetscReal seqval; 521 PetscBool isseq; 522 523 PetscFunctionBegin; 524 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 525 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 526 PetscCall(VecGetDM(v, &dm)); 527 PetscCall(DMGetLocalSection(dm, §ion)); 528 PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, &seqval)); 529 PetscCall(DMSequenceView_HDF5(dm, "time", seqnum, (PetscScalar)seqval, viewer)); 530 if (seqnum >= 0) { 531 PetscCall(PetscViewerHDF5PushTimestepping(viewer)); 532 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); 533 } 534 PetscCall(PetscViewerGetFormat(viewer, &format)); 535 PetscCall(DMGetOutputDM(dm, &dmBC)); 536 PetscCall(DMGetGlobalSection(dmBC, §ionGlobal)); 537 PetscCall(DMGetGlobalVector(dmBC, &gv)); 538 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 539 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 540 PetscCall(DMLocalToGlobalBegin(dmBC, v, INSERT_VALUES, gv)); 541 PetscCall(DMLocalToGlobalEnd(dmBC, v, INSERT_VALUES, gv)); 542 PetscCall(PetscObjectTypeCompare((PetscObject)gv, VECSEQ, &isseq)); 543 if (format == PETSC_VIEWER_HDF5_VIZ) { 544 /* Output visualization representation */ 545 PetscInt numFields, f; 546 DMLabel cutLabel, cutVertexLabel = NULL; 547 548 PetscCall(PetscSectionGetNumFields(section, &numFields)); 549 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 550 for (f = 0; f < numFields; ++f) { 551 Vec subv; 552 IS is; 553 const char *fname, *fgroup, *componentName, *fname_def = "unnamed"; 554 char subname[PETSC_MAX_PATH_LEN]; 555 PetscInt Nc, Nt = 1; 556 PetscInt *pStart, *pEnd; 557 PetscViewerVTKFieldType *ft; 558 559 if (DMPlexStorageVersionEQ(version, 1, 1, 0)) PetscCall(DMPlexGetFieldTypes_Internal(dm, section, f, &Nt, &pStart, &pEnd, &ft)); 560 else { 561 PetscCall(PetscMalloc3(Nt, &pStart, Nt, &pEnd, Nt, &ft)); 562 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart[0], &pEnd[0], &ft[0])); 563 } 564 for (PetscInt t = 0; t < Nt; ++t) { 565 if (ft[t] == PETSC_VTK_INVALID) continue; 566 fgroup = (ft[t] == PETSC_VTK_POINT_VECTOR_FIELD) || (ft[t] == PETSC_VTK_POINT_FIELD) ? "/vertex_fields" : "/cell_fields"; 567 PetscCall(PetscSectionGetFieldName(section, f, &fname)); 568 if (!fname) fname = fname_def; 569 570 if (!t) { 571 PetscCall(PetscViewerHDF5PushGroup(viewer, fgroup)); 572 } else { 573 char group[PETSC_MAX_PATH_LEN]; 574 575 PetscCall(PetscSNPrintf(group, PETSC_MAX_PATH_LEN, "%s_%" PetscInt_FMT, fgroup, t)); 576 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 577 } 578 579 if (cutLabel) { 580 const PetscScalar *ga; 581 PetscScalar *suba; 582 PetscInt gstart, subSize = 0, extSize = 0, subOff = 0, newOff = 0; 583 584 PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel)); 585 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 586 for (PetscInt p = pStart[t]; p < pEnd[t]; ++p) { 587 PetscInt gdof, fdof = 0, val; 588 589 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 590 if (gdof > 0) PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 591 subSize += fdof; 592 PetscCall(DMLabelGetValue(cutVertexLabel, p, &val)); 593 if (val == 1) extSize += fdof; 594 } 595 PetscCall(VecCreate(PetscObjectComm((PetscObject)gv), &subv)); 596 PetscCall(VecSetSizes(subv, subSize + extSize, PETSC_DETERMINE)); 597 PetscCall(VecSetBlockSize(subv, Nc)); 598 PetscCall(VecSetType(subv, VECSTANDARD)); 599 PetscCall(VecGetOwnershipRange(gv, &gstart, NULL)); 600 PetscCall(VecGetArrayRead(gv, &ga)); 601 PetscCall(VecGetArray(subv, &suba)); 602 for (PetscInt p = pStart[t]; p < pEnd[t]; ++p) { 603 PetscInt gdof, goff, val; 604 605 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 606 if (gdof > 0) { 607 PetscInt fdof, fc, f2, poff = 0; 608 609 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff)); 610 /* Can get rid of this loop by storing field information in the global section */ 611 for (f2 = 0; f2 < f; ++f2) { 612 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 613 poff += fdof; 614 } 615 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 616 for (fc = 0; fc < fdof; ++fc, ++subOff) suba[subOff] = ga[goff + poff + fc - gstart]; 617 PetscCall(DMLabelGetValue(cutVertexLabel, p, &val)); 618 if (val == 1) { 619 for (fc = 0; fc < fdof; ++fc, ++newOff) suba[subSize + newOff] = ga[goff + poff + fc - gstart]; 620 } 621 } 622 } 623 PetscCall(VecRestoreArrayRead(gv, &ga)); 624 PetscCall(VecRestoreArray(subv, &suba)); 625 PetscCall(DMLabelDestroy(&cutVertexLabel)); 626 } else { 627 PetscCall(PetscSectionGetField_Internal(section, sectionGlobal, gv, f, pStart[t], pEnd[t], &is, &subv)); 628 } 629 PetscCall(PetscStrncpy(subname, name, sizeof(subname))); 630 PetscCall(PetscStrlcat(subname, "_", sizeof(subname))); 631 PetscCall(PetscStrlcat(subname, fname, sizeof(subname))); 632 PetscCall(PetscObjectSetName((PetscObject)subv, subname)); 633 if (isseq) PetscCall(VecView_Seq(subv, viewer)); 634 else PetscCall(VecView_MPI(subv, viewer)); 635 if (ft[t] == PETSC_VTK_POINT_VECTOR_FIELD || ft[t] == PETSC_VTK_CELL_VECTOR_FIELD) { 636 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, "vector_field_type", PETSC_STRING, "vector")); 637 } else { 638 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, "vector_field_type", PETSC_STRING, "scalar")); 639 } 640 641 /* Output the component names in the field if available */ 642 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 643 for (PetscInt c = 0; c < Nc; ++c) { 644 char componentNameLabel[PETSC_MAX_PATH_LEN]; 645 PetscCall(PetscSectionGetComponentName(section, f, c, &componentName)); 646 PetscCall(PetscSNPrintf(componentNameLabel, sizeof(componentNameLabel), "componentName%" PetscInt_FMT, c)); 647 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)subv, componentNameLabel, PETSC_STRING, componentName)); 648 } 649 650 if (cutLabel) PetscCall(VecDestroy(&subv)); 651 else PetscCall(PetscSectionRestoreField_Internal(section, sectionGlobal, gv, f, pStart[t], pEnd[t], &is, &subv)); 652 PetscCall(PetscViewerHDF5PopGroup(viewer)); 653 } 654 if (!DMPlexStorageVersionEQ(version, 1, 1, 0)) PetscCall(PetscFree3(pStart, pEnd, ft)); 655 } 656 } else { 657 /* Output full vector */ 658 PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields")); 659 if (isseq) PetscCall(VecView_Seq(gv, viewer)); 660 else PetscCall(VecView_MPI(gv, viewer)); 661 PetscCall(PetscViewerHDF5PopGroup(viewer)); 662 } 663 if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer)); 664 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 665 PetscFunctionReturn(PETSC_SUCCESS); 666 } 667 668 PetscErrorCode VecView_Plex_HDF5_Internal(Vec v, PetscViewer viewer) 669 { 670 DMPlexStorageVersion version; 671 DM dm; 672 Vec locv; 673 PetscObject isZero; 674 const char *name; 675 PetscReal time; 676 677 PetscFunctionBegin; 678 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 679 PetscCall(PetscInfo(v, "Writing Vec %s storage version %d.%d.%d\n", v->hdr.name, version->major, version->minor, version->subminor)); 680 681 PetscCall(VecGetDM(v, &dm)); 682 PetscCall(DMGetLocalVector(dm, &locv)); 683 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 684 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 685 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 686 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 687 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 688 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 689 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 690 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 691 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 692 if (DMPlexStorageVersionEQ(version, 1, 1, 0)) { 693 PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields")); 694 PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ)); 695 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 696 PetscCall(PetscViewerPopFormat(viewer)); 697 PetscCall(PetscViewerHDF5PopGroup(viewer)); 698 } 699 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 700 PetscCall(DMRestoreLocalVector(dm, &locv)); 701 PetscFunctionReturn(PETSC_SUCCESS); 702 } 703 704 PetscErrorCode VecView_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer) 705 { 706 PetscBool isseq; 707 708 PetscFunctionBegin; 709 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 710 PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields")); 711 if (isseq) PetscCall(VecView_Seq(v, viewer)); 712 else PetscCall(VecView_MPI(v, viewer)); 713 PetscCall(PetscViewerHDF5PopGroup(viewer)); 714 PetscFunctionReturn(PETSC_SUCCESS); 715 } 716 717 PetscErrorCode VecLoad_Plex_HDF5_Internal(Vec v, PetscViewer viewer) 718 { 719 DM dm; 720 Vec locv; 721 const char *name; 722 PetscInt seqnum; 723 724 PetscFunctionBegin; 725 PetscCall(VecGetDM(v, &dm)); 726 PetscCall(DMGetLocalVector(dm, &locv)); 727 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 728 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 729 PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, NULL)); 730 PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields")); 731 if (seqnum >= 0) { 732 PetscCall(PetscViewerHDF5PushTimestepping(viewer)); 733 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); 734 } 735 PetscCall(VecLoad_Plex_Local(locv, viewer)); 736 if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer)); 737 PetscCall(PetscViewerHDF5PopGroup(viewer)); 738 PetscCall(DMLocalToGlobalBegin(dm, locv, INSERT_VALUES, v)); 739 PetscCall(DMLocalToGlobalEnd(dm, locv, INSERT_VALUES, v)); 740 PetscCall(DMRestoreLocalVector(dm, &locv)); 741 PetscFunctionReturn(PETSC_SUCCESS); 742 } 743 744 PetscErrorCode VecLoad_Plex_HDF5_Native_Internal(Vec v, PetscViewer viewer) 745 { 746 DM dm; 747 PetscInt seqnum; 748 749 PetscFunctionBegin; 750 PetscCall(VecGetDM(v, &dm)); 751 PetscCall(DMGetOutputSequenceNumber(dm, &seqnum, NULL)); 752 PetscCall(PetscViewerHDF5PushGroup(viewer, "/fields")); 753 if (seqnum >= 0) { 754 PetscCall(PetscViewerHDF5PushTimestepping(viewer)); 755 PetscCall(PetscViewerHDF5SetTimestep(viewer, seqnum)); 756 } 757 PetscCall(VecLoad_Default(v, viewer)); 758 if (seqnum >= 0) PetscCall(PetscViewerHDF5PopTimestepping(viewer)); 759 PetscCall(PetscViewerHDF5PopGroup(viewer)); 760 PetscFunctionReturn(PETSC_SUCCESS); 761 } 762 763 static PetscErrorCode DMPlexDistributionView_HDF5_Private(DM dm, IS globalPointNumbers, PetscViewer viewer) 764 { 765 DMPlexStorageVersion version; 766 MPI_Comm comm; 767 PetscMPIInt size, rank; 768 PetscInt size_petsc_int; 769 const char *topologydm_name, *distribution_name; 770 const PetscInt *gpoint; 771 PetscInt pStart, pEnd, p; 772 PetscSF pointSF; 773 PetscInt nroots, nleaves; 774 const PetscInt *ilocal; 775 const PetscSFNode *iremote; 776 IS chartSizesIS, ownersIS, gpointsIS; 777 PetscInt *chartSize, *owners, *gpoints; 778 779 PetscFunctionBegin; 780 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 781 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 782 PetscCallMPI(MPI_Comm_size(comm, &size)); 783 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 784 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 785 PetscCall(DMPlexDistributionGetName(dm, &distribution_name)); 786 if (!distribution_name) PetscFunctionReturn(PETSC_SUCCESS); 787 PetscCall(PetscLogEventBegin(DMPLEX_DistributionView, viewer, 0, 0, 0)); 788 size_petsc_int = (PetscInt)size; 789 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "comm_size", PETSC_INT, (void *)&size_petsc_int)); 790 PetscCall(ISGetIndices(globalPointNumbers, &gpoint)); 791 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 792 PetscCall(PetscMalloc1(1, &chartSize)); 793 *chartSize = pEnd - pStart; 794 PetscCall(PetscMalloc1(*chartSize, &owners)); 795 PetscCall(PetscMalloc1(*chartSize, &gpoints)); 796 PetscCall(DMGetPointSF(dm, &pointSF)); 797 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote)); 798 for (p = pStart; p < pEnd; ++p) { 799 PetscInt gp = gpoint[p - pStart]; 800 801 owners[p - pStart] = rank; 802 gpoints[p - pStart] = (gp < 0 ? -(gp + 1) : gp); 803 } 804 for (p = 0; p < nleaves; ++p) { 805 PetscInt ilocalp = (ilocal ? ilocal[p] : p); 806 807 owners[ilocalp] = iremote[p].rank; 808 } 809 PetscCall(ISCreateGeneral(comm, 1, chartSize, PETSC_OWN_POINTER, &chartSizesIS)); 810 PetscCall(ISCreateGeneral(comm, *chartSize, owners, PETSC_OWN_POINTER, &ownersIS)); 811 PetscCall(ISCreateGeneral(comm, *chartSize, gpoints, PETSC_OWN_POINTER, &gpointsIS)); 812 if (DMPlexStorageVersionGE(version, 3, 1, 0)) { 813 PetscCall(ISSetCompressOutput(chartSizesIS, PETSC_TRUE)); 814 PetscCall(ISSetCompressOutput(ownersIS, PETSC_TRUE)); 815 PetscCall(ISSetCompressOutput(gpointsIS, PETSC_TRUE)); 816 } 817 PetscCall(PetscObjectSetName((PetscObject)chartSizesIS, "chart_sizes")); 818 PetscCall(PetscObjectSetName((PetscObject)ownersIS, "owners")); 819 PetscCall(PetscObjectSetName((PetscObject)gpointsIS, "global_point_numbers")); 820 PetscCall(ISView(chartSizesIS, viewer)); 821 PetscCall(ISView(ownersIS, viewer)); 822 PetscCall(ISView(gpointsIS, viewer)); 823 PetscCall(ISDestroy(&chartSizesIS)); 824 PetscCall(ISDestroy(&ownersIS)); 825 PetscCall(ISDestroy(&gpointsIS)); 826 PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint)); 827 PetscCall(PetscLogEventEnd(DMPLEX_DistributionView, viewer, 0, 0, 0)); 828 PetscFunctionReturn(PETSC_SUCCESS); 829 } 830 831 static PetscErrorCode DMPlexTopologyView_HDF5_Inner_Private(DM dm, IS globalPointNumbers, PetscViewer viewer, PetscInt pStart, PetscInt pEnd, const char pointsName[], const char coneSizesName[], const char conesName[], const char orientationsName[]) 832 { 833 DMPlexStorageVersion version; 834 IS coneSizesIS, conesIS, orientationsIS; 835 PetscInt *coneSizes, *cones, *orientations; 836 const PetscInt *gpoint; 837 PetscInt nPoints = 0, conesSize = 0; 838 PetscInt p, c, s; 839 MPI_Comm comm; 840 841 PetscFunctionBegin; 842 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 843 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 844 PetscCall(ISGetIndices(globalPointNumbers, &gpoint)); 845 for (p = pStart; p < pEnd; ++p) { 846 if (gpoint[p] >= 0) { 847 PetscInt coneSize; 848 849 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 850 nPoints += 1; 851 conesSize += coneSize; 852 } 853 } 854 PetscCall(PetscMalloc1(nPoints, &coneSizes)); 855 PetscCall(PetscMalloc1(conesSize, &cones)); 856 PetscCall(PetscMalloc1(conesSize, &orientations)); 857 for (p = pStart, c = 0, s = 0; p < pEnd; ++p) { 858 if (gpoint[p] >= 0) { 859 const PetscInt *cone, *ornt; 860 PetscInt coneSize, cp; 861 862 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 863 PetscCall(DMPlexGetCone(dm, p, &cone)); 864 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 865 coneSizes[s] = coneSize; 866 for (cp = 0; cp < coneSize; ++cp, ++c) { 867 cones[c] = gpoint[cone[cp]] < 0 ? -(gpoint[cone[cp]] + 1) : gpoint[cone[cp]]; 868 orientations[c] = ornt[cp]; 869 } 870 ++s; 871 } 872 } 873 PetscCheck(s == nPoints, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of points %" PetscInt_FMT " != %" PetscInt_FMT, s, nPoints); 874 PetscCheck(c == conesSize, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of cone points %" PetscInt_FMT " != %" PetscInt_FMT, c, conesSize); 875 PetscCall(ISCreateGeneral(comm, nPoints, coneSizes, PETSC_OWN_POINTER, &coneSizesIS)); 876 PetscCall(ISCreateGeneral(comm, conesSize, cones, PETSC_OWN_POINTER, &conesIS)); 877 PetscCall(ISCreateGeneral(comm, conesSize, orientations, PETSC_OWN_POINTER, &orientationsIS)); 878 PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName)); 879 PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName)); 880 PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName)); 881 if (DMPlexStorageVersionGE(version, 3, 1, 0)) { 882 PetscCall(ISSetCompressOutput(coneSizesIS, PETSC_TRUE)); 883 PetscCall(ISSetCompressOutput(conesIS, PETSC_TRUE)); 884 PetscCall(ISSetCompressOutput(orientationsIS, PETSC_TRUE)); 885 } 886 PetscCall(ISView(coneSizesIS, viewer)); 887 PetscCall(ISView(conesIS, viewer)); 888 PetscCall(ISView(orientationsIS, viewer)); 889 PetscCall(ISDestroy(&coneSizesIS)); 890 PetscCall(ISDestroy(&conesIS)); 891 PetscCall(ISDestroy(&orientationsIS)); 892 if (pointsName) { 893 IS pointsIS; 894 PetscInt *points; 895 896 PetscCall(PetscMalloc1(nPoints, &points)); 897 for (p = pStart, c = 0, s = 0; p < pEnd; ++p) { 898 if (gpoint[p] >= 0) { 899 points[s] = gpoint[p]; 900 ++s; 901 } 902 } 903 PetscCall(ISCreateGeneral(comm, nPoints, points, PETSC_OWN_POINTER, &pointsIS)); 904 PetscCall(PetscObjectSetName((PetscObject)pointsIS, pointsName)); 905 if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(pointsIS, PETSC_TRUE)); 906 PetscCall(ISView(pointsIS, viewer)); 907 PetscCall(ISDestroy(&pointsIS)); 908 } 909 PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint)); 910 PetscFunctionReturn(PETSC_SUCCESS); 911 } 912 913 static PetscErrorCode DMPlexTopologyView_HDF5_Legacy_Private(DM dm, IS globalPointNumbers, PetscViewer viewer) 914 { 915 const char *pointsName, *coneSizesName, *conesName, *orientationsName; 916 PetscInt pStart, pEnd, dim; 917 918 PetscFunctionBegin; 919 pointsName = "order"; 920 coneSizesName = "cones"; 921 conesName = "cells"; 922 orientationsName = "orientation"; 923 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 924 PetscCall(DMPlexTopologyView_HDF5_Inner_Private(dm, globalPointNumbers, viewer, pStart, pEnd, pointsName, coneSizesName, conesName, orientationsName)); 925 PetscCall(DMGetDimension(dm, &dim)); 926 PetscCall(PetscViewerHDF5WriteAttribute(viewer, conesName, "cell_dim", PETSC_INT, (void *)&dim)); 927 PetscFunctionReturn(PETSC_SUCCESS); 928 } 929 930 //TODO get this numbering right away without needing this function 931 /* Renumber global point numbers so that they are 0-based per stratum */ 932 static PetscErrorCode RenumberGlobalPointNumbersPerStratum_Private(DM dm, IS globalPointNumbers, IS *newGlobalPointNumbers, IS *strataPermutation) 933 { 934 PetscInt d, depth, p, n; 935 PetscInt *offsets; 936 const PetscInt *gpn; 937 PetscInt *ngpn; 938 MPI_Comm comm; 939 940 PetscFunctionBegin; 941 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 942 PetscCall(ISGetLocalSize(globalPointNumbers, &n)); 943 PetscCall(ISGetIndices(globalPointNumbers, &gpn)); 944 PetscCall(PetscMalloc1(n, &ngpn)); 945 PetscCall(DMPlexGetDepth(dm, &depth)); 946 PetscCall(PetscMalloc1(depth + 1, &offsets)); 947 for (d = 0; d <= depth; d++) { 948 PetscInt pStart, pEnd; 949 950 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 951 offsets[d] = PETSC_INT_MAX; 952 for (p = pStart; p < pEnd; p++) { 953 if (gpn[p] >= 0 && gpn[p] < offsets[d]) offsets[d] = gpn[p]; 954 } 955 } 956 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, offsets, depth + 1, MPIU_INT, MPI_MIN, comm)); 957 for (d = 0; d <= depth; d++) { 958 PetscInt pStart, pEnd; 959 960 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 961 for (p = pStart; p < pEnd; p++) ngpn[p] = gpn[p] - PetscSign(gpn[p]) * offsets[d]; 962 } 963 PetscCall(ISRestoreIndices(globalPointNumbers, &gpn)); 964 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)globalPointNumbers), n, ngpn, PETSC_OWN_POINTER, newGlobalPointNumbers)); 965 { 966 PetscInt *perm; 967 968 PetscCall(PetscMalloc1(depth + 1, &perm)); 969 for (d = 0; d <= depth; d++) perm[d] = d; 970 PetscCall(PetscSortIntWithPermutation(depth + 1, offsets, perm)); 971 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, depth + 1, perm, PETSC_OWN_POINTER, strataPermutation)); 972 } 973 PetscCall(PetscFree(offsets)); 974 PetscFunctionReturn(PETSC_SUCCESS); 975 } 976 977 static PetscErrorCode DMPlexTopologyView_HDF5_Private(DM dm, IS globalPointNumbers, PetscViewer viewer) 978 { 979 IS globalPointNumbers0, strataPermutation; 980 const char *coneSizesName, *conesName, *orientationsName; 981 PetscInt depth, d; 982 MPI_Comm comm; 983 984 PetscFunctionBegin; 985 coneSizesName = "cone_sizes"; 986 conesName = "cones"; 987 orientationsName = "orientations"; 988 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 989 PetscCall(DMPlexGetDepth(dm, &depth)); 990 { 991 PetscInt dim; 992 993 PetscCall(DMGetDimension(dm, &dim)); 994 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "cell_dim", PETSC_INT, &dim)); 995 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "depth", PETSC_INT, &depth)); 996 } 997 998 PetscCall(RenumberGlobalPointNumbersPerStratum_Private(dm, globalPointNumbers, &globalPointNumbers0, &strataPermutation)); 999 /* TODO dirty trick to save serial IS using the same parallel viewer */ 1000 { 1001 IS spOnComm; 1002 PetscInt n = 0, N; 1003 const PetscInt *idx = NULL; 1004 const PetscInt *old; 1005 PetscMPIInt rank; 1006 1007 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1008 PetscCall(ISGetLocalSize(strataPermutation, &N)); 1009 PetscCall(ISGetIndices(strataPermutation, &old)); 1010 if (!rank) { 1011 n = N; 1012 idx = old; 1013 } 1014 PetscCall(ISCreateGeneral(comm, n, idx, PETSC_COPY_VALUES, &spOnComm)); 1015 PetscCall(ISRestoreIndices(strataPermutation, &old)); 1016 PetscCall(ISDestroy(&strataPermutation)); 1017 strataPermutation = spOnComm; 1018 } 1019 PetscCall(PetscObjectSetName((PetscObject)strataPermutation, "permutation")); 1020 PetscCall(ISView(strataPermutation, viewer)); 1021 PetscCall(PetscViewerHDF5PushGroup(viewer, "strata")); 1022 for (d = 0; d <= depth; d++) { 1023 PetscInt pStart, pEnd; 1024 char group[128]; 1025 1026 PetscCall(PetscSNPrintf(group, sizeof(group), "%" PetscInt_FMT, d)); 1027 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1028 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1029 PetscCall(DMPlexTopologyView_HDF5_Inner_Private(dm, globalPointNumbers0, viewer, pStart, pEnd, NULL, coneSizesName, conesName, orientationsName)); 1030 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1031 } 1032 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* strata */ 1033 PetscCall(ISDestroy(&globalPointNumbers0)); 1034 PetscCall(ISDestroy(&strataPermutation)); 1035 PetscFunctionReturn(PETSC_SUCCESS); 1036 } 1037 1038 PetscErrorCode DMPlexTopologyView_HDF5_Internal(DM dm, IS globalPointNumbers, PetscViewer viewer) 1039 { 1040 DMPlexStorageVersion version; 1041 const char *topologydm_name; 1042 char group[PETSC_MAX_PATH_LEN]; 1043 1044 PetscFunctionBegin; 1045 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 1046 PetscCall(PetscInfo(dm, "Writing DM %s storage version %d.%d.%d\n", dm->hdr.name, version->major, version->minor, version->subminor)); 1047 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1048 if (DMPlexStorageVersionGE(version, 2, 0, 0)) { 1049 PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s", topologydm_name)); 1050 } else { 1051 PetscCall(PetscStrncpy(group, "/", sizeof(group))); 1052 } 1053 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1054 1055 PetscCall(PetscViewerHDF5PushGroup(viewer, "topology")); 1056 if (version->major < 3) { 1057 PetscCall(DMPlexTopologyView_HDF5_Legacy_Private(dm, globalPointNumbers, viewer)); 1058 } else { 1059 /* since DMPlexStorageVersion 3.0.0 */ 1060 PetscCall(DMPlexTopologyView_HDF5_Private(dm, globalPointNumbers, viewer)); 1061 } 1062 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "topology" */ 1063 1064 if (DMPlexStorageVersionGE(version, 2, 1, 0)) { 1065 const char *distribution_name; 1066 1067 PetscCall(DMPlexDistributionGetName(dm, &distribution_name)); 1068 PetscCall(PetscViewerHDF5PushGroup(viewer, "distributions")); 1069 PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL)); 1070 PetscCall(PetscViewerHDF5PushGroup(viewer, distribution_name)); 1071 PetscCall(DMPlexDistributionView_HDF5_Private(dm, globalPointNumbers, viewer)); 1072 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* distribution_name */ 1073 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "distributions" */ 1074 } 1075 1076 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1077 PetscFunctionReturn(PETSC_SUCCESS); 1078 } 1079 1080 static PetscErrorCode CreateConesIS_Private(DM dm, PetscInt cStart, PetscInt cEnd, IS globalCellNumbers, PetscInt *numCorners, IS *cellIS) 1081 { 1082 PetscSF sfPoint; 1083 DMLabel cutLabel, cutVertexLabel = NULL; 1084 IS globalVertexNumbers, cutvertices = NULL; 1085 const PetscInt *gcell, *gvertex, *cutverts = NULL; 1086 PetscInt *vertices; 1087 PetscInt conesSize = 0; 1088 PetscInt dim, numCornersLocal = 0, cell, vStart, vEnd, vExtra = 0, v; 1089 1090 PetscFunctionBegin; 1091 *numCorners = 0; 1092 PetscCall(DMGetDimension(dm, &dim)); 1093 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1094 PetscCall(ISGetIndices(globalCellNumbers, &gcell)); 1095 1096 for (cell = cStart; cell < cEnd; ++cell) { 1097 PetscInt *closure = NULL; 1098 PetscInt closureSize, v, Nc = 0; 1099 1100 if (gcell[cell] < 0) continue; 1101 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1102 for (v = 0; v < closureSize * 2; v += 2) { 1103 if ((closure[v] >= vStart) && (closure[v] < vEnd)) ++Nc; 1104 } 1105 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1106 conesSize += Nc; 1107 if (!numCornersLocal) numCornersLocal = Nc; 1108 else if (numCornersLocal != Nc) numCornersLocal = 1; 1109 } 1110 PetscCallMPI(MPIU_Allreduce(&numCornersLocal, numCorners, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 1111 PetscCheck(!numCornersLocal || !(numCornersLocal != *numCorners || *numCorners == 0), PETSC_COMM_SELF, PETSC_ERR_SUP, "Visualization topology currently only supports identical cell shapes"); 1112 /* Handle periodic cuts by identifying vertices which should be duplicated */ 1113 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1114 PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel)); 1115 if (cutVertexLabel) PetscCall(DMLabelGetStratumIS(cutVertexLabel, 1, &cutvertices)); 1116 if (cutvertices) { 1117 PetscCall(ISGetIndices(cutvertices, &cutverts)); 1118 PetscCall(ISGetLocalSize(cutvertices, &vExtra)); 1119 } 1120 PetscCall(DMGetPointSF(dm, &sfPoint)); 1121 if (cutLabel) { 1122 const PetscInt *ilocal; 1123 const PetscSFNode *iremote; 1124 PetscInt nroots, nleaves; 1125 1126 PetscCall(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &ilocal, &iremote)); 1127 if (nleaves < 0) { 1128 PetscCall(PetscObjectReference((PetscObject)sfPoint)); 1129 } else { 1130 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfPoint), &sfPoint)); 1131 PetscCall(PetscSFSetGraph(sfPoint, nroots + vExtra, nleaves, (PetscInt *)ilocal, PETSC_COPY_VALUES, (PetscSFNode *)iremote, PETSC_COPY_VALUES)); 1132 } 1133 } else { 1134 PetscCall(PetscObjectReference((PetscObject)sfPoint)); 1135 } 1136 /* Number all vertices */ 1137 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd + vExtra, 0, NULL, sfPoint, &globalVertexNumbers)); 1138 PetscCall(PetscSFDestroy(&sfPoint)); 1139 /* Create cones */ 1140 PetscCall(ISGetIndices(globalVertexNumbers, &gvertex)); 1141 PetscCall(PetscMalloc1(conesSize, &vertices)); 1142 for (cell = cStart, v = 0; cell < cEnd; ++cell) { 1143 PetscInt *closure = NULL; 1144 PetscInt closureSize, Nc = 0, p, value = -1; 1145 PetscBool replace; 1146 1147 if (gcell[cell] < 0) continue; 1148 if (cutLabel) PetscCall(DMLabelGetValue(cutLabel, cell, &value)); 1149 replace = (value == 2) ? PETSC_TRUE : PETSC_FALSE; 1150 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1151 for (p = 0; p < closureSize * 2; p += 2) { 1152 if ((closure[p] >= vStart) && (closure[p] < vEnd)) closure[Nc++] = closure[p]; 1153 } 1154 PetscCall(DMPlexReorderCell(dm, cell, closure)); 1155 for (p = 0; p < Nc; ++p) { 1156 PetscInt nv, gv = gvertex[closure[p] - vStart]; 1157 1158 if (replace) { 1159 PetscCall(PetscFindInt(closure[p], vExtra, cutverts, &nv)); 1160 if (nv >= 0) gv = gvertex[vEnd - vStart + nv]; 1161 } 1162 vertices[v++] = gv < 0 ? -(gv + 1) : gv; 1163 } 1164 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1165 } 1166 PetscCall(ISRestoreIndices(globalVertexNumbers, &gvertex)); 1167 PetscCall(ISDestroy(&globalVertexNumbers)); 1168 PetscCall(ISRestoreIndices(globalCellNumbers, &gcell)); 1169 if (cutvertices) PetscCall(ISRestoreIndices(cutvertices, &cutverts)); 1170 PetscCall(ISDestroy(&cutvertices)); 1171 PetscCall(DMLabelDestroy(&cutVertexLabel)); 1172 PetscCheck(v == conesSize, PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of cell vertices %" PetscInt_FMT " != %" PetscInt_FMT, v, conesSize); 1173 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), conesSize, vertices, PETSC_OWN_POINTER, cellIS)); 1174 PetscCall(PetscLayoutSetBlockSize((*cellIS)->map, *numCorners)); 1175 PetscCall(PetscObjectSetName((PetscObject)*cellIS, "cells")); 1176 PetscFunctionReturn(PETSC_SUCCESS); 1177 } 1178 1179 static PetscErrorCode DMPlexTopologyView_HDF5_XDMF_Private(DM dm, IS globalCellNumbers, PetscViewer viewer) 1180 { 1181 DM cdm; 1182 DMLabel depthLabel, ctLabel; 1183 IS cellIS; 1184 PetscInt dim, depth, cellHeight, c, n = 0; 1185 1186 PetscFunctionBegin; 1187 PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz")); 1188 PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL)); 1189 1190 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1191 PetscCall(DMGetDimension(dm, &dim)); 1192 PetscCall(DMPlexGetDepth(dm, &depth)); 1193 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1194 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1195 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 1196 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 1197 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 1198 const DMPolytopeType ict = (DMPolytopeType)c; 1199 PetscInt pStart, pEnd, dep, numCorners; 1200 PetscBool output = PETSC_FALSE, doOutput; 1201 1202 if (ict == DM_POLYTOPE_FV_GHOST) continue; 1203 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &pStart, &pEnd)); 1204 if (pStart >= 0) { 1205 PetscCall(DMLabelGetValue(depthLabel, pStart, &dep)); 1206 if (dep == depth - cellHeight) output = PETSC_TRUE; 1207 } 1208 PetscCallMPI(MPIU_Allreduce(&output, &doOutput, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 1209 if (!doOutput) continue; 1210 PetscCall(CreateConesIS_Private(dm, pStart, pEnd, globalCellNumbers, &numCorners, &cellIS)); 1211 if (!n) { 1212 PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz/topology")); 1213 } else { 1214 char group[PETSC_MAX_PATH_LEN]; 1215 1216 PetscCall(PetscSNPrintf(group, PETSC_MAX_PATH_LEN, "/viz/topology_%" PetscInt_FMT, n)); 1217 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1218 } 1219 PetscCall(ISView(cellIS, viewer)); 1220 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)cellIS, "cell_corners", PETSC_INT, (void *)&numCorners)); 1221 PetscCall(PetscViewerHDF5WriteObjectAttribute(viewer, (PetscObject)cellIS, "cell_dim", PETSC_INT, (void *)&dim)); 1222 PetscCall(ISDestroy(&cellIS)); 1223 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1224 ++n; 1225 } 1226 PetscFunctionReturn(PETSC_SUCCESS); 1227 } 1228 1229 static PetscErrorCode DMPlexCoordinatesView_HDF5_Legacy_Private(DM dm, PetscViewer viewer) 1230 { 1231 DM cdm; 1232 Vec coordinates, newcoords; 1233 PetscReal lengthScale; 1234 PetscInt m, M, bs; 1235 1236 PetscFunctionBegin; 1237 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 1238 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1239 PetscCall(DMGetCoordinates(dm, &coordinates)); 1240 PetscCall(VecCreate(PetscObjectComm((PetscObject)coordinates), &newcoords)); 1241 PetscCall(PetscObjectSetName((PetscObject)newcoords, "vertices")); 1242 PetscCall(VecGetSize(coordinates, &M)); 1243 PetscCall(VecGetLocalSize(coordinates, &m)); 1244 PetscCall(VecSetSizes(newcoords, m, M)); 1245 PetscCall(VecGetBlockSize(coordinates, &bs)); 1246 PetscCall(VecSetBlockSize(newcoords, bs)); 1247 PetscCall(VecSetType(newcoords, VECSTANDARD)); 1248 PetscCall(VecCopy(coordinates, newcoords)); 1249 PetscCall(VecScale(newcoords, lengthScale)); 1250 /* Did not use DMGetGlobalVector() in order to bypass default group assignment */ 1251 PetscCall(PetscViewerHDF5PushGroup(viewer, "/geometry")); 1252 PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE)); 1253 PetscCall(VecView(newcoords, viewer)); 1254 PetscCall(PetscViewerPopFormat(viewer)); 1255 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1256 PetscCall(VecDestroy(&newcoords)); 1257 PetscFunctionReturn(PETSC_SUCCESS); 1258 } 1259 1260 PetscErrorCode DMPlexCoordinatesView_HDF5_Internal(DM dm, PetscViewer viewer) 1261 { 1262 DM cdm; 1263 Vec coords, newcoords; 1264 PetscInt m, M, bs; 1265 PetscReal lengthScale; 1266 PetscBool viewSection = PETSC_TRUE; 1267 const char *topologydm_name, *coordinatedm_name, *coordinates_name; 1268 1269 PetscFunctionBegin; 1270 { 1271 PetscViewerFormat format; 1272 DMPlexStorageVersion version; 1273 1274 PetscCall(PetscViewerGetFormat(viewer, &format)); 1275 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 1276 if (!DMPlexStorageVersionGE(version, 2, 0, 0) || format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 1277 PetscCall(DMPlexCoordinatesView_HDF5_Legacy_Private(dm, viewer)); 1278 PetscFunctionReturn(PETSC_SUCCESS); 1279 } 1280 } 1281 /* since 2.0.0 */ 1282 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_view_coordinate_section", &viewSection, NULL)); 1283 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1284 PetscCall(DMGetCoordinates(dm, &coords)); 1285 PetscCall(PetscObjectGetName((PetscObject)cdm, &coordinatedm_name)); 1286 PetscCall(PetscObjectGetName((PetscObject)coords, &coordinates_name)); 1287 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1288 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 1289 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 1290 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "coordinateDMName", PETSC_STRING, coordinatedm_name)); 1291 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "coordinatesName", PETSC_STRING, coordinates_name)); 1292 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1293 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1294 if (viewSection) PetscCall(DMPlexSectionView(dm, viewer, cdm)); 1295 PetscCall(VecCreate(PetscObjectComm((PetscObject)coords), &newcoords)); 1296 PetscCall(PetscObjectSetName((PetscObject)newcoords, coordinates_name)); 1297 PetscCall(VecGetSize(coords, &M)); 1298 PetscCall(VecGetLocalSize(coords, &m)); 1299 PetscCall(VecSetSizes(newcoords, m, M)); 1300 PetscCall(VecGetBlockSize(coords, &bs)); 1301 PetscCall(VecSetBlockSize(newcoords, bs)); 1302 PetscCall(VecSetType(newcoords, VECSTANDARD)); 1303 PetscCall(VecCopy(coords, newcoords)); 1304 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 1305 PetscCall(VecScale(newcoords, lengthScale)); 1306 PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE)); 1307 PetscCall(DMPlexGlobalVectorView(dm, viewer, cdm, newcoords)); 1308 PetscCall(PetscViewerPopFormat(viewer)); 1309 PetscCall(VecDestroy(&newcoords)); 1310 PetscFunctionReturn(PETSC_SUCCESS); 1311 } 1312 1313 static PetscErrorCode DMPlexCoordinatesView_HDF5_XDMF_Private(DM dm, PetscViewer viewer) 1314 { 1315 DM cdm; 1316 Vec coordinatesLocal, newcoords; 1317 PetscSection cSection, cGlobalSection; 1318 PetscScalar *coords, *ncoords; 1319 DMLabel cutLabel, cutVertexLabel = NULL; 1320 const PetscReal *L; 1321 PetscReal lengthScale; 1322 PetscInt vStart, vEnd, v, bs, N, coordSize, dof, off, d; 1323 PetscBool localized, embedded; 1324 1325 PetscFunctionBegin; 1326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1327 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 1328 PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal)); 1329 PetscCall(VecGetBlockSize(coordinatesLocal, &bs)); 1330 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1331 if (localized == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS); 1332 PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L)); 1333 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1334 PetscCall(DMGetLocalSection(cdm, &cSection)); 1335 PetscCall(DMGetGlobalSection(cdm, &cGlobalSection)); 1336 PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel)); 1337 N = 0; 1338 1339 PetscCall(DMPlexCreateCutVertexLabel_Private(dm, cutLabel, &cutVertexLabel)); 1340 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &newcoords)); 1341 PetscCall(PetscSectionGetDof(cSection, vStart, &dof)); 1342 PetscCall(PetscPrintf(PETSC_COMM_SELF, "DOF: %" PetscInt_FMT "\n", dof)); 1343 embedded = (PetscBool)(L && dof == 2 && !cutLabel); 1344 if (cutVertexLabel) { 1345 PetscCall(DMLabelGetStratumSize(cutVertexLabel, 1, &v)); 1346 N += dof * v; 1347 } 1348 for (v = vStart; v < vEnd; ++v) { 1349 PetscCall(PetscSectionGetDof(cGlobalSection, v, &dof)); 1350 if (dof < 0) continue; 1351 if (embedded) N += dof + 1; 1352 else N += dof; 1353 } 1354 if (embedded) PetscCall(VecSetBlockSize(newcoords, bs + 1)); 1355 else PetscCall(VecSetBlockSize(newcoords, bs)); 1356 PetscCall(VecSetSizes(newcoords, N, PETSC_DETERMINE)); 1357 PetscCall(VecSetType(newcoords, VECSTANDARD)); 1358 PetscCall(VecGetArray(coordinatesLocal, &coords)); 1359 PetscCall(VecGetArray(newcoords, &ncoords)); 1360 coordSize = 0; 1361 for (v = vStart; v < vEnd; ++v) { 1362 PetscCall(PetscSectionGetDof(cGlobalSection, v, &dof)); 1363 PetscCall(PetscSectionGetOffset(cSection, v, &off)); 1364 if (dof < 0) continue; 1365 if (embedded) { 1366 if (L && (L[0] > 0.0) && (L[1] > 0.0)) { 1367 PetscReal theta, phi, r, R; 1368 /* XY-periodic */ 1369 /* Suppose its an y-z circle, then 1370 \hat r = (0, cos(th), sin(th)) \hat x = (1, 0, 0) 1371 and the circle in that plane is 1372 \hat r cos(phi) + \hat x sin(phi) */ 1373 theta = 2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1]; 1374 phi = 2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0]; 1375 r = L[0] / (2.0 * PETSC_PI * 2.0 * L[1]); 1376 R = L[1] / (2.0 * PETSC_PI); 1377 ncoords[coordSize++] = PetscSinReal(phi) * r; 1378 ncoords[coordSize++] = -PetscCosReal(theta) * (R + r * PetscCosReal(phi)); 1379 ncoords[coordSize++] = PetscSinReal(theta) * (R + r * PetscCosReal(phi)); 1380 } else if (L && (L[0] > 0.0)) { 1381 /* X-periodic */ 1382 ncoords[coordSize++] = -PetscCosReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0]) * (L[0] / (2.0 * PETSC_PI)); 1383 ncoords[coordSize++] = coords[off + 1]; 1384 ncoords[coordSize++] = PetscSinReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 0]) / L[0]) * (L[0] / (2.0 * PETSC_PI)); 1385 } else if (L && (L[1] > 0.0)) { 1386 /* Y-periodic */ 1387 ncoords[coordSize++] = coords[off + 0]; 1388 ncoords[coordSize++] = PetscSinReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1]) * (L[1] / (2.0 * PETSC_PI)); 1389 ncoords[coordSize++] = -PetscCosReal(2.0 * PETSC_PI * PetscRealPart(coords[off + 1]) / L[1]) * (L[1] / (2.0 * PETSC_PI)); 1390 #if 0 1391 } else if ((bd[0] == DM_BOUNDARY_TWIST)) { 1392 PetscReal phi, r, R; 1393 /* Mobius strip */ 1394 /* Suppose its an x-z circle, then 1395 \hat r = (-cos(phi), 0, sin(phi)) \hat y = (0, 1, 0) 1396 and in that plane we rotate by pi as we go around the circle 1397 \hat r cos(phi/2) + \hat y sin(phi/2) */ 1398 phi = 2.0*PETSC_PI*PetscRealPart(coords[off+0])/L[0]; 1399 R = L[0]; 1400 r = PetscRealPart(coords[off+1]) - L[1]/2.0; 1401 ncoords[coordSize++] = -PetscCosReal(phi) * (R + r * PetscCosReal(phi/2.0)); 1402 ncoords[coordSize++] = PetscSinReal(phi/2.0) * r; 1403 ncoords[coordSize++] = PetscSinReal(phi) * (R + r * PetscCosReal(phi/2.0)); 1404 #endif 1405 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot handle periodicity in this domain"); 1406 } else { 1407 for (d = 0; d < dof; ++d, ++coordSize) ncoords[coordSize] = coords[off + d]; 1408 } 1409 } 1410 if (cutVertexLabel) { 1411 IS vertices; 1412 const PetscInt *verts; 1413 PetscInt n; 1414 1415 PetscCall(DMLabelGetStratumIS(cutVertexLabel, 1, &vertices)); 1416 if (vertices) { 1417 PetscCall(ISGetIndices(vertices, &verts)); 1418 PetscCall(ISGetLocalSize(vertices, &n)); 1419 for (v = 0; v < n; ++v) { 1420 PetscCall(PetscSectionGetDof(cSection, verts[v], &dof)); 1421 PetscCall(PetscSectionGetOffset(cSection, verts[v], &off)); 1422 for (d = 0; d < dof; ++d) ncoords[coordSize++] = coords[off + d] + ((L[d] > 0.) ? L[d] : 0.0); 1423 } 1424 PetscCall(ISRestoreIndices(vertices, &verts)); 1425 PetscCall(ISDestroy(&vertices)); 1426 } 1427 } 1428 PetscCheck(coordSize == N, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched sizes: %" PetscInt_FMT " != %" PetscInt_FMT, coordSize, N); 1429 PetscCall(DMLabelDestroy(&cutVertexLabel)); 1430 PetscCall(VecRestoreArray(coordinatesLocal, &coords)); 1431 PetscCall(VecRestoreArray(newcoords, &ncoords)); 1432 PetscCall(PetscObjectSetName((PetscObject)newcoords, "vertices")); 1433 PetscCall(VecScale(newcoords, lengthScale)); 1434 PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz")); 1435 PetscCall(PetscViewerHDF5WriteGroup(viewer, NULL)); 1436 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1437 PetscCall(PetscViewerHDF5PushGroup(viewer, "/viz/geometry")); 1438 PetscCall(VecView(newcoords, viewer)); 1439 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1440 PetscCall(VecDestroy(&newcoords)); 1441 PetscFunctionReturn(PETSC_SUCCESS); 1442 } 1443 1444 PetscErrorCode DMPlexLabelsView_HDF5_Internal(DM dm, IS globalPointNumbers, PetscViewer viewer) 1445 { 1446 const char *topologydm_name; 1447 const PetscInt *gpoint; 1448 PetscInt numLabels; 1449 PetscBool omitCelltypes = PETSC_FALSE; 1450 DMPlexStorageVersion version; 1451 char group[PETSC_MAX_PATH_LEN]; 1452 1453 PetscFunctionBegin; 1454 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_omit_celltypes", &omitCelltypes, NULL)); 1455 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 1456 PetscCall(ISGetIndices(globalPointNumbers, &gpoint)); 1457 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1458 if (DMPlexStorageVersionGE(version, 2, 0, 0)) { 1459 PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s/labels", topologydm_name)); 1460 } else { 1461 PetscCall(PetscStrncpy(group, "/labels", sizeof(group))); 1462 } 1463 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1464 PetscCall(DMGetNumLabels(dm, &numLabels)); 1465 for (PetscInt l = 0; l < numLabels; ++l) { 1466 DMLabel label; 1467 const char *name; 1468 IS valueIS, pvalueIS, globalValueIS; 1469 const PetscInt *values; 1470 PetscInt numValues, v; 1471 PetscBool isDepth, isCelltype, output; 1472 1473 PetscCall(DMGetLabelByNum(dm, l, &label)); 1474 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 1475 PetscCall(DMGetLabelOutput(dm, name, &output)); 1476 PetscCall(PetscStrncmp(name, "depth", 10, &isDepth)); 1477 PetscCall(PetscStrncmp(name, "celltype", 10, &isCelltype)); 1478 // TODO Should only filter out celltype if it can be calculated 1479 if (isDepth || (isCelltype && omitCelltypes) || !output) continue; 1480 PetscCall(PetscViewerHDF5PushGroup(viewer, name)); 1481 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1482 /* Must copy to a new IS on the global comm */ 1483 PetscCall(ISGetLocalSize(valueIS, &numValues)); 1484 PetscCall(ISGetIndices(valueIS, &values)); 1485 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), numValues, values, PETSC_COPY_VALUES, &pvalueIS)); 1486 PetscCall(ISRestoreIndices(valueIS, &values)); 1487 PetscCall(ISAllGather(pvalueIS, &globalValueIS)); 1488 PetscCall(ISDestroy(&pvalueIS)); 1489 PetscCall(ISSortRemoveDups(globalValueIS)); 1490 PetscCall(ISGetLocalSize(globalValueIS, &numValues)); 1491 PetscCall(ISGetIndices(globalValueIS, &values)); 1492 for (v = 0; v < numValues; ++v) { 1493 IS stratumIS, globalStratumIS; 1494 const PetscInt *spoints = NULL; 1495 PetscInt *gspoints, n = 0, gn, p; 1496 const char *iname = "indices"; 1497 char group[PETSC_MAX_PATH_LEN]; 1498 1499 PetscCall(PetscSNPrintf(group, sizeof(group), "%" PetscInt_FMT, values[v])); 1500 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1501 PetscCall(DMLabelGetStratumIS(label, values[v], &stratumIS)); 1502 1503 if (stratumIS) PetscCall(ISGetLocalSize(stratumIS, &n)); 1504 if (stratumIS) PetscCall(ISGetIndices(stratumIS, &spoints)); 1505 for (gn = 0, p = 0; p < n; ++p) 1506 if (gpoint[spoints[p]] >= 0) ++gn; 1507 PetscCall(PetscMalloc1(gn, &gspoints)); 1508 for (gn = 0, p = 0; p < n; ++p) 1509 if (gpoint[spoints[p]] >= 0) gspoints[gn++] = gpoint[spoints[p]]; 1510 if (stratumIS) PetscCall(ISRestoreIndices(stratumIS, &spoints)); 1511 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), gn, gspoints, PETSC_OWN_POINTER, &globalStratumIS)); 1512 PetscCall(PetscObjectSetName((PetscObject)globalStratumIS, iname)); 1513 if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(globalStratumIS, PETSC_TRUE)); 1514 1515 PetscCall(ISView(globalStratumIS, viewer)); 1516 PetscCall(ISDestroy(&globalStratumIS)); 1517 PetscCall(ISDestroy(&stratumIS)); 1518 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1519 } 1520 PetscCall(ISRestoreIndices(globalValueIS, &values)); 1521 PetscCall(ISDestroy(&globalValueIS)); 1522 PetscCall(ISDestroy(&valueIS)); 1523 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1524 } 1525 PetscCall(ISRestoreIndices(globalPointNumbers, &gpoint)); 1526 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1527 PetscFunctionReturn(PETSC_SUCCESS); 1528 } 1529 1530 /* We only write cells and vertices. Does this screw up parallel reading? */ 1531 PetscErrorCode DMPlexView_HDF5_Internal(DM dm, PetscViewer viewer) 1532 { 1533 IS globalPointNumbers; 1534 PetscViewerFormat format; 1535 PetscBool viz_geom = PETSC_FALSE, xdmf_topo = PETSC_FALSE, petsc_topo = PETSC_FALSE; 1536 1537 PetscFunctionBegin; 1538 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbers)); 1539 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1540 1541 PetscCall(PetscViewerGetFormat(viewer, &format)); 1542 switch (format) { 1543 case PETSC_VIEWER_HDF5_VIZ: 1544 viz_geom = PETSC_TRUE; 1545 xdmf_topo = PETSC_TRUE; 1546 break; 1547 case PETSC_VIEWER_HDF5_XDMF: 1548 xdmf_topo = PETSC_TRUE; 1549 break; 1550 case PETSC_VIEWER_HDF5_PETSC: 1551 petsc_topo = PETSC_TRUE; 1552 break; 1553 case PETSC_VIEWER_DEFAULT: 1554 case PETSC_VIEWER_NATIVE: 1555 viz_geom = PETSC_TRUE; 1556 xdmf_topo = PETSC_TRUE; 1557 petsc_topo = PETSC_TRUE; 1558 break; 1559 default: 1560 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1561 } 1562 1563 if (viz_geom) PetscCall(DMPlexCoordinatesView_HDF5_XDMF_Private(dm, viewer)); 1564 if (xdmf_topo) PetscCall(DMPlexTopologyView_HDF5_XDMF_Private(dm, globalPointNumbers, viewer)); 1565 if (petsc_topo) { 1566 PetscBool viewLabels = PETSC_TRUE; 1567 1568 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbers, viewer)); 1569 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_view_labels", &viewLabels, NULL)); 1570 if (viewLabels) PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbers, viewer)); 1571 } 1572 1573 PetscCall(ISDestroy(&globalPointNumbers)); 1574 PetscFunctionReturn(PETSC_SUCCESS); 1575 } 1576 1577 PetscErrorCode DMPlexSectionView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm) 1578 { 1579 DMPlexStorageVersion version; 1580 MPI_Comm comm; 1581 const char *topologydm_name; 1582 const char *sectiondm_name; 1583 PetscSection gsection; 1584 1585 PetscFunctionBegin; 1586 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionWriting(viewer, &version)); 1587 PetscCall(PetscObjectGetComm((PetscObject)sectiondm, &comm)); 1588 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1589 PetscCall(PetscObjectGetName((PetscObject)sectiondm, §iondm_name)); 1590 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 1591 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 1592 PetscCall(PetscViewerHDF5PushGroup(viewer, "dms")); 1593 PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name)); 1594 PetscCall(DMGetGlobalSection(sectiondm, &gsection)); 1595 /* Save raw section */ 1596 PetscCall(PetscSectionView(gsection, viewer)); 1597 /* Save plex wrapper */ 1598 { 1599 PetscInt pStart, pEnd, p, n; 1600 IS globalPointNumbers; 1601 const PetscInt *gpoints; 1602 IS orderIS; 1603 PetscInt *order; 1604 1605 PetscCall(PetscSectionGetChart(gsection, &pStart, &pEnd)); 1606 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbers)); 1607 PetscCall(ISGetIndices(globalPointNumbers, &gpoints)); 1608 for (p = pStart, n = 0; p < pEnd; ++p) 1609 if (gpoints[p] >= 0) n++; 1610 /* "order" is an array of global point numbers. 1611 When loading, it is used with topology/order array 1612 to match section points with plex topology points. */ 1613 PetscCall(PetscMalloc1(n, &order)); 1614 for (p = pStart, n = 0; p < pEnd; ++p) 1615 if (gpoints[p] >= 0) order[n++] = gpoints[p]; 1616 PetscCall(ISRestoreIndices(globalPointNumbers, &gpoints)); 1617 PetscCall(ISDestroy(&globalPointNumbers)); 1618 PetscCall(ISCreateGeneral(comm, n, order, PETSC_OWN_POINTER, &orderIS)); 1619 PetscCall(PetscObjectSetName((PetscObject)orderIS, "order")); 1620 if (DMPlexStorageVersionGE(version, 3, 1, 0)) PetscCall(ISSetCompressOutput(orderIS, PETSC_TRUE)); 1621 PetscCall(ISView(orderIS, viewer)); 1622 PetscCall(ISDestroy(&orderIS)); 1623 } 1624 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1625 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1626 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1627 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1628 PetscFunctionReturn(PETSC_SUCCESS); 1629 } 1630 1631 PetscErrorCode DMPlexGlobalVectorView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1632 { 1633 const char *topologydm_name; 1634 const char *sectiondm_name; 1635 const char *vec_name; 1636 PetscInt bs; 1637 1638 PetscFunctionBegin; 1639 /* Check consistency */ 1640 { 1641 PetscSF pointsf, pointsf1; 1642 1643 PetscCall(DMGetPointSF(dm, &pointsf)); 1644 PetscCall(DMGetPointSF(sectiondm, &pointsf1)); 1645 PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm"); 1646 } 1647 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1648 PetscCall(PetscObjectGetName((PetscObject)sectiondm, §iondm_name)); 1649 PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name)); 1650 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 1651 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 1652 PetscCall(PetscViewerHDF5PushGroup(viewer, "dms")); 1653 PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name)); 1654 PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs")); 1655 PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name)); 1656 PetscCall(VecGetBlockSize(vec, &bs)); 1657 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "blockSize", PETSC_INT, (void *)&bs)); 1658 PetscCall(VecSetBlockSize(vec, 1)); 1659 /* VecView(vec, viewer) would call (*vec->opt->view)(vec, viewer), but, */ 1660 /* if vec was created with DMGet{Global, Local}Vector(), vec->opt->view */ 1661 /* is set to VecView_Plex, which would save vec in a predefined location. */ 1662 /* To save vec in where we want, we create a new Vec (temp) with */ 1663 /* VecCreate(), wrap the vec data in temp, and call VecView(temp, viewer). */ 1664 { 1665 Vec temp; 1666 const PetscScalar *array; 1667 PetscLayout map; 1668 1669 PetscCall(VecCreate(PetscObjectComm((PetscObject)vec), &temp)); 1670 PetscCall(PetscObjectSetName((PetscObject)temp, vec_name)); 1671 PetscCall(VecGetLayout(vec, &map)); 1672 PetscCall(VecSetLayout(temp, map)); 1673 PetscCall(VecSetUp(temp)); 1674 PetscCall(VecGetArrayRead(vec, &array)); 1675 PetscCall(VecPlaceArray(temp, array)); 1676 PetscCall(VecView(temp, viewer)); 1677 PetscCall(VecResetArray(temp)); 1678 PetscCall(VecRestoreArrayRead(vec, &array)); 1679 PetscCall(VecDestroy(&temp)); 1680 } 1681 PetscCall(VecSetBlockSize(vec, bs)); 1682 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1683 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1684 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1685 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1686 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1687 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1688 PetscFunctionReturn(PETSC_SUCCESS); 1689 } 1690 1691 PetscErrorCode DMPlexLocalVectorView_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1692 { 1693 MPI_Comm comm; 1694 const char *topologydm_name; 1695 const char *sectiondm_name; 1696 const char *vec_name; 1697 PetscSection section; 1698 PetscBool includesConstraints; 1699 Vec gvec; 1700 PetscInt m, bs; 1701 1702 PetscFunctionBegin; 1703 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1704 /* Check consistency */ 1705 { 1706 PetscSF pointsf, pointsf1; 1707 1708 PetscCall(DMGetPointSF(dm, &pointsf)); 1709 PetscCall(DMGetPointSF(sectiondm, &pointsf1)); 1710 PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm"); 1711 } 1712 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1713 PetscCall(PetscObjectGetName((PetscObject)sectiondm, §iondm_name)); 1714 PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name)); 1715 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 1716 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 1717 PetscCall(PetscViewerHDF5PushGroup(viewer, "dms")); 1718 PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name)); 1719 PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs")); 1720 PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name)); 1721 PetscCall(VecGetBlockSize(vec, &bs)); 1722 PetscCall(PetscViewerHDF5WriteAttribute(viewer, NULL, "blockSize", PETSC_INT, (void *)&bs)); 1723 PetscCall(VecCreate(comm, &gvec)); 1724 PetscCall(PetscObjectSetName((PetscObject)gvec, vec_name)); 1725 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1726 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1727 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1728 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1729 PetscCall(VecSetSizes(gvec, m, PETSC_DECIDE)); 1730 PetscCall(VecSetUp(gvec)); 1731 PetscCall(DMLocalToGlobalBegin(sectiondm, vec, INSERT_VALUES, gvec)); 1732 PetscCall(DMLocalToGlobalEnd(sectiondm, vec, INSERT_VALUES, gvec)); 1733 PetscCall(VecView(gvec, viewer)); 1734 PetscCall(VecDestroy(&gvec)); 1735 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1736 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1737 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1738 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1739 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1740 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1741 PetscFunctionReturn(PETSC_SUCCESS); 1742 } 1743 1744 struct _n_LoadLabelsCtx { 1745 MPI_Comm comm; 1746 PetscMPIInt rank; 1747 DM dm; 1748 PetscViewer viewer; 1749 DMLabel label; 1750 PetscSF sfXC; 1751 PetscLayout layoutX; 1752 }; 1753 typedef struct _n_LoadLabelsCtx *LoadLabelsCtx; 1754 1755 static PetscErrorCode LoadLabelsCtxCreate(DM dm, PetscViewer viewer, PetscSF sfXC, LoadLabelsCtx *ctx) 1756 { 1757 PetscFunctionBegin; 1758 PetscCall(PetscNew(ctx)); 1759 PetscCall(PetscObjectReference((PetscObject)((*ctx)->dm = dm))); 1760 PetscCall(PetscObjectReference((PetscObject)((*ctx)->viewer = viewer))); 1761 PetscCall(PetscObjectGetComm((PetscObject)dm, &(*ctx)->comm)); 1762 PetscCallMPI(MPI_Comm_rank((*ctx)->comm, &(*ctx)->rank)); 1763 (*ctx)->sfXC = sfXC; 1764 if (sfXC) { 1765 PetscInt nX; 1766 1767 PetscCall(PetscObjectReference((PetscObject)sfXC)); 1768 PetscCall(PetscSFGetGraph(sfXC, &nX, NULL, NULL, NULL)); 1769 PetscCall(PetscLayoutCreateFromSizes((*ctx)->comm, nX, PETSC_DECIDE, 1, &(*ctx)->layoutX)); 1770 } 1771 PetscFunctionReturn(PETSC_SUCCESS); 1772 } 1773 1774 static PetscErrorCode LoadLabelsCtxDestroy(LoadLabelsCtx *ctx) 1775 { 1776 PetscFunctionBegin; 1777 if (!*ctx) PetscFunctionReturn(PETSC_SUCCESS); 1778 PetscCall(DMDestroy(&(*ctx)->dm)); 1779 PetscCall(PetscViewerDestroy(&(*ctx)->viewer)); 1780 PetscCall(PetscSFDestroy(&(*ctx)->sfXC)); 1781 PetscCall(PetscLayoutDestroy(&(*ctx)->layoutX)); 1782 PetscCall(PetscFree(*ctx)); 1783 PetscFunctionReturn(PETSC_SUCCESS); 1784 } 1785 1786 /* 1787 A: on-disk points 1788 X: global points [0, NX) 1789 C: distributed plex points 1790 */ 1791 static herr_t ReadLabelStratumHDF5_Distribute_Private(IS stratumIS, LoadLabelsCtx ctx, IS *newStratumIS) 1792 { 1793 MPI_Comm comm = ctx->comm; 1794 PetscSF sfXC = ctx->sfXC; 1795 PetscLayout layoutX = ctx->layoutX; 1796 PetscSF sfXA; 1797 const PetscInt *A_points; 1798 PetscInt nX, nC; 1799 PetscInt n; 1800 1801 PetscFunctionBegin; 1802 PetscCall(PetscSFGetGraph(sfXC, &nX, &nC, NULL, NULL)); 1803 PetscCall(ISGetLocalSize(stratumIS, &n)); 1804 PetscCall(ISGetIndices(stratumIS, &A_points)); 1805 PetscCall(PetscSFCreate(comm, &sfXA)); 1806 PetscCall(PetscSFSetGraphLayout(sfXA, layoutX, n, NULL, PETSC_USE_POINTER, A_points)); 1807 PetscCall(ISCreate(comm, newStratumIS)); 1808 PetscCall(ISSetType(*newStratumIS, ISGENERAL)); 1809 { 1810 PetscInt i; 1811 PetscBool *A_mask, *X_mask, *C_mask; 1812 1813 PetscCall(PetscCalloc3(n, &A_mask, nX, &X_mask, nC, &C_mask)); 1814 for (i = 0; i < n; i++) A_mask[i] = PETSC_TRUE; 1815 PetscCall(PetscSFReduceBegin(sfXA, MPIU_BOOL, A_mask, X_mask, MPI_REPLACE)); 1816 PetscCall(PetscSFReduceEnd(sfXA, MPIU_BOOL, A_mask, X_mask, MPI_REPLACE)); 1817 PetscCall(PetscSFBcastBegin(sfXC, MPIU_BOOL, X_mask, C_mask, MPI_LOR)); 1818 PetscCall(PetscSFBcastEnd(sfXC, MPIU_BOOL, X_mask, C_mask, MPI_LOR)); 1819 PetscCall(ISGeneralSetIndicesFromMask(*newStratumIS, 0, nC, C_mask)); 1820 PetscCall(PetscFree3(A_mask, X_mask, C_mask)); 1821 } 1822 PetscCall(PetscSFDestroy(&sfXA)); 1823 PetscCall(ISRestoreIndices(stratumIS, &A_points)); 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 static herr_t ReadLabelStratumHDF5_Static(hid_t g_id, const char *vname, const H5L_info_t *info, void *op_data) 1828 { 1829 LoadLabelsCtx ctx = (LoadLabelsCtx)op_data; 1830 PetscViewer viewer = ctx->viewer; 1831 DMLabel label = ctx->label; 1832 MPI_Comm comm = ctx->comm; 1833 IS stratumIS; 1834 const PetscInt *ind; 1835 PetscInt value, N, i; 1836 1837 PetscCall(PetscOptionsStringToInt(vname, &value)); 1838 PetscCall(ISCreate(comm, &stratumIS)); 1839 PetscCall(PetscObjectSetName((PetscObject)stratumIS, "indices")); 1840 PetscCall(PetscViewerHDF5PushGroup(viewer, vname)); /* labels/<lname>/<vname> */ 1841 1842 if (!ctx->sfXC) { 1843 /* Force serial load */ 1844 PetscCall(PetscViewerHDF5ReadSizes(viewer, "indices", NULL, &N)); 1845 PetscCall(PetscLayoutSetLocalSize(stratumIS->map, !ctx->rank ? N : 0)); 1846 PetscCall(PetscLayoutSetSize(stratumIS->map, N)); 1847 } 1848 PetscCall(ISLoad(stratumIS, viewer)); 1849 1850 if (ctx->sfXC) { 1851 IS newStratumIS; 1852 1853 PetscCallHDF5(ReadLabelStratumHDF5_Distribute_Private, (stratumIS, ctx, &newStratumIS)); 1854 PetscCall(ISDestroy(&stratumIS)); 1855 stratumIS = newStratumIS; 1856 } 1857 1858 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1859 PetscCall(ISGetLocalSize(stratumIS, &N)); 1860 PetscCall(ISGetIndices(stratumIS, &ind)); 1861 for (i = 0; i < N; ++i) PetscCall(DMLabelSetValue(label, ind[i], value)); 1862 PetscCall(ISRestoreIndices(stratumIS, &ind)); 1863 PetscCall(ISDestroy(&stratumIS)); 1864 return 0; 1865 } 1866 1867 /* TODO: Fix this code, it is returning PETSc error codes when it should be translating them to herr_t codes */ 1868 static herr_t ReadLabelHDF5_Static(hid_t g_id, const char *lname, const H5L_info_t *info, void *op_data) 1869 { 1870 LoadLabelsCtx ctx = (LoadLabelsCtx)op_data; 1871 DM dm = ctx->dm; 1872 hsize_t idx = 0; 1873 PetscErrorCode ierr; 1874 PetscBool flg; 1875 herr_t err; 1876 1877 PetscCall(DMHasLabel(dm, lname, &flg)); 1878 if (flg) PetscCall(DMRemoveLabel(dm, lname, NULL)); 1879 ierr = DMCreateLabel(dm, lname); 1880 if (ierr) return (herr_t)ierr; 1881 ierr = DMGetLabel(dm, lname, &ctx->label); 1882 if (ierr) return (herr_t)ierr; 1883 ierr = PetscViewerHDF5PushGroup(ctx->viewer, lname); 1884 if (ierr) return (herr_t)ierr; 1885 /* Iterate over the label's strata */ 1886 PetscCallHDF5Return(err, H5Literate_by_name, (g_id, lname, H5_INDEX_NAME, H5_ITER_NATIVE, &idx, ReadLabelStratumHDF5_Static, op_data, 0)); 1887 ierr = PetscViewerHDF5PopGroup(ctx->viewer); 1888 if (ierr) return (herr_t)ierr; 1889 return err; 1890 } 1891 1892 PetscErrorCode DMPlexLabelsLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF sfXC) 1893 { 1894 const char *topologydm_name; 1895 LoadLabelsCtx ctx; 1896 hsize_t idx = 0; 1897 char group[PETSC_MAX_PATH_LEN]; 1898 DMPlexStorageVersion version; 1899 PetscBool distributed, hasGroup; 1900 1901 PetscFunctionBegin; 1902 PetscCall(DMPlexIsDistributed(dm, &distributed)); 1903 if (distributed) PetscCheck(sfXC, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "PetscSF must be given for parallel load"); 1904 PetscCall(LoadLabelsCtxCreate(dm, viewer, sfXC, &ctx)); 1905 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 1906 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version)); 1907 if (DMPlexStorageVersionGE(version, 2, 0, 0)) { 1908 PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s/labels", topologydm_name)); 1909 } else { 1910 PetscCall(PetscStrncpy(group, "labels", sizeof(group))); 1911 } 1912 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 1913 PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &hasGroup)); 1914 if (hasGroup) { 1915 hid_t fileId, groupId; 1916 1917 PetscCall(PetscViewerHDF5OpenGroup(viewer, NULL, &fileId, &groupId)); 1918 /* Iterate over labels */ 1919 PetscCallHDF5(H5Literate, (groupId, H5_INDEX_NAME, H5_ITER_NATIVE, &idx, ReadLabelHDF5_Static, ctx)); 1920 PetscCallHDF5(H5Gclose, (groupId)); 1921 } 1922 PetscCall(PetscViewerHDF5PopGroup(viewer)); 1923 PetscCall(LoadLabelsCtxDestroy(&ctx)); 1924 PetscFunctionReturn(PETSC_SUCCESS); 1925 } 1926 1927 static PetscErrorCode DMPlexDistributionLoad_HDF5_Private(DM dm, PetscViewer viewer, PetscSF sf, PetscSF *distsf, DM *distdm) 1928 { 1929 MPI_Comm comm; 1930 PetscMPIInt size, rank; 1931 PetscInt dist_size; 1932 const char *distribution_name; 1933 PetscInt p, lsize; 1934 IS chartSizesIS, ownersIS, gpointsIS; 1935 const PetscInt *chartSize, *owners, *gpoints; 1936 PetscLayout layout; 1937 PetscBool has; 1938 1939 PetscFunctionBegin; 1940 *distsf = NULL; 1941 *distdm = NULL; 1942 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1943 PetscCallMPI(MPI_Comm_size(comm, &size)); 1944 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1945 PetscCall(DMPlexDistributionGetName(dm, &distribution_name)); 1946 if (!distribution_name) PetscFunctionReturn(PETSC_SUCCESS); 1947 PetscCall(PetscLogEventBegin(DMPLEX_DistributionLoad, viewer, 0, 0, 0)); 1948 PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &has)); 1949 if (!has) { 1950 const char *full_group; 1951 1952 PetscCall(PetscViewerHDF5GetGroup(viewer, NULL, &full_group)); 1953 PetscCheck(has, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Distribution %s cannot be found: HDF5 group %s not found in file", distribution_name, full_group); 1954 } 1955 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "comm_size", PETSC_INT, NULL, (void *)&dist_size)); 1956 PetscCheck(dist_size == (PetscInt)size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mismatching comm sizes: comm size of this session (%d) != comm size used for %s (%" PetscInt_FMT ")", size, distribution_name, dist_size); 1957 PetscCall(ISCreate(comm, &chartSizesIS)); 1958 PetscCall(PetscObjectSetName((PetscObject)chartSizesIS, "chart_sizes")); 1959 PetscCall(ISCreate(comm, &ownersIS)); 1960 PetscCall(PetscObjectSetName((PetscObject)ownersIS, "owners")); 1961 PetscCall(ISCreate(comm, &gpointsIS)); 1962 PetscCall(PetscObjectSetName((PetscObject)gpointsIS, "global_point_numbers")); 1963 PetscCall(PetscLayoutSetLocalSize(chartSizesIS->map, 1)); 1964 PetscCall(ISLoad(chartSizesIS, viewer)); 1965 PetscCall(ISGetIndices(chartSizesIS, &chartSize)); 1966 PetscCall(PetscLayoutSetLocalSize(ownersIS->map, *chartSize)); 1967 PetscCall(PetscLayoutSetLocalSize(gpointsIS->map, *chartSize)); 1968 PetscCall(ISLoad(ownersIS, viewer)); 1969 PetscCall(ISLoad(gpointsIS, viewer)); 1970 PetscCall(ISGetIndices(ownersIS, &owners)); 1971 PetscCall(ISGetIndices(gpointsIS, &gpoints)); 1972 PetscCall(PetscSFCreate(comm, distsf)); 1973 PetscCall(PetscSFSetFromOptions(*distsf)); 1974 PetscCall(PetscLayoutCreate(comm, &layout)); 1975 PetscCall(PetscSFGetGraph(sf, &lsize, NULL, NULL, NULL)); 1976 PetscCall(PetscLayoutSetLocalSize(layout, lsize)); 1977 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 1978 PetscCall(PetscLayoutSetUp(layout)); 1979 PetscCall(PetscSFSetGraphLayout(*distsf, layout, *chartSize, NULL, PETSC_OWN_POINTER, gpoints)); 1980 PetscCall(PetscLayoutDestroy(&layout)); 1981 /* Migrate DM */ 1982 { 1983 PetscInt pStart, pEnd; 1984 PetscSFNode *buffer0, *buffer1, *buffer2; 1985 1986 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1987 PetscCall(PetscMalloc2(pEnd - pStart, &buffer0, lsize, &buffer1)); 1988 PetscCall(PetscMalloc1(*chartSize, &buffer2)); 1989 { 1990 PetscSF workPointSF; 1991 PetscInt workNroots, workNleaves; 1992 const PetscInt *workIlocal; 1993 const PetscSFNode *workIremote; 1994 1995 for (p = pStart; p < pEnd; ++p) { 1996 buffer0[p - pStart].rank = rank; 1997 buffer0[p - pStart].index = p - pStart; 1998 } 1999 PetscCall(DMGetPointSF(dm, &workPointSF)); 2000 PetscCall(PetscSFGetGraph(workPointSF, &workNroots, &workNleaves, &workIlocal, &workIremote)); 2001 for (p = 0; p < workNleaves; ++p) { 2002 PetscInt workIlocalp = (workIlocal ? workIlocal[p] : p); 2003 2004 buffer0[workIlocalp].rank = -1; 2005 } 2006 } 2007 for (p = 0; p < lsize; ++p) buffer1[p].rank = -1; 2008 for (p = 0; p < *chartSize; ++p) buffer2[p].rank = -1; 2009 PetscCall(PetscSFReduceBegin(sf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC)); 2010 PetscCall(PetscSFReduceEnd(sf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC)); 2011 PetscCall(PetscSFBcastBegin(*distsf, MPIU_SF_NODE, buffer1, buffer2, MPI_REPLACE)); 2012 PetscCall(PetscSFBcastEnd(*distsf, MPIU_SF_NODE, buffer1, buffer2, MPI_REPLACE)); 2013 if (PetscDefined(USE_DEBUG)) { 2014 for (p = 0; p < *chartSize; ++p) { 2015 PetscCheck(buffer2[p].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Found negative root rank %" PetscInt_FMT " at local point %" PetscInt_FMT " on rank %d when making migrationSF", buffer2[p].rank, p, rank); 2016 } 2017 } 2018 PetscCall(PetscFree2(buffer0, buffer1)); 2019 PetscCall(DMCreate(comm, distdm)); 2020 PetscCall(DMSetType(*distdm, DMPLEX)); 2021 PetscCall(PetscObjectSetName((PetscObject)*distdm, ((PetscObject)dm)->name)); 2022 PetscCall(DMPlexDistributionSetName(*distdm, distribution_name)); 2023 { 2024 PetscSF migrationSF; 2025 2026 PetscCall(PetscSFCreate(comm, &migrationSF)); 2027 PetscCall(PetscSFSetFromOptions(migrationSF)); 2028 PetscCall(PetscSFSetGraph(migrationSF, pEnd - pStart, *chartSize, NULL, PETSC_OWN_POINTER, buffer2, PETSC_OWN_POINTER)); 2029 PetscCall(PetscSFSetUp(migrationSF)); 2030 PetscCall(DMPlexMigrate(dm, migrationSF, *distdm)); 2031 PetscCall(PetscSFDestroy(&migrationSF)); 2032 } 2033 } 2034 /* Set pointSF */ 2035 { 2036 PetscSF pointSF; 2037 PetscInt *ilocal, nleaves, q; 2038 PetscSFNode *iremote, *buffer0, *buffer1; 2039 2040 PetscCall(PetscMalloc2(*chartSize, &buffer0, lsize, &buffer1)); 2041 for (p = 0, nleaves = 0; p < *chartSize; ++p) { 2042 if (owners[p] == rank) { 2043 buffer0[p].rank = rank; 2044 } else { 2045 buffer0[p].rank = -1; 2046 nleaves++; 2047 } 2048 buffer0[p].index = p; 2049 } 2050 for (p = 0; p < lsize; ++p) buffer1[p].rank = -1; 2051 PetscCall(PetscSFReduceBegin(*distsf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC)); 2052 PetscCall(PetscSFReduceEnd(*distsf, MPIU_SF_NODE, buffer0, buffer1, MPI_MAXLOC)); 2053 for (p = 0; p < *chartSize; ++p) buffer0[p].rank = -1; 2054 PetscCall(PetscSFBcastBegin(*distsf, MPIU_SF_NODE, buffer1, buffer0, MPI_REPLACE)); 2055 PetscCall(PetscSFBcastEnd(*distsf, MPIU_SF_NODE, buffer1, buffer0, MPI_REPLACE)); 2056 if (PetscDefined(USE_DEBUG)) { 2057 for (p = 0; p < *chartSize; ++p) PetscCheck(buffer0[p].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Found negative root rank %" PetscInt_FMT " at local point %" PetscInt_FMT " on rank %d when making pointSF", buffer0[p].rank, p, rank); 2058 } 2059 PetscCall(PetscMalloc1(nleaves, &ilocal)); 2060 PetscCall(PetscMalloc1(nleaves, &iremote)); 2061 for (p = 0, q = 0; p < *chartSize; ++p) { 2062 if (buffer0[p].rank != rank) { 2063 ilocal[q] = p; 2064 iremote[q].rank = buffer0[p].rank; 2065 iremote[q].index = buffer0[p].index; 2066 q++; 2067 } 2068 } 2069 PetscCheck(q == nleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching leaf sizes: %" PetscInt_FMT " != %" PetscInt_FMT, q, nleaves); 2070 PetscCall(PetscFree2(buffer0, buffer1)); 2071 PetscCall(PetscSFCreate(comm, &pointSF)); 2072 PetscCall(PetscSFSetFromOptions(pointSF)); 2073 PetscCall(PetscSFSetGraph(pointSF, *chartSize, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 2074 PetscCall(DMSetPointSF(*distdm, pointSF)); 2075 { 2076 DM cdm; 2077 2078 PetscCall(DMGetCoordinateDM(*distdm, &cdm)); 2079 PetscCall(DMSetPointSF(cdm, pointSF)); 2080 } 2081 PetscCall(PetscSFDestroy(&pointSF)); 2082 } 2083 PetscCall(ISRestoreIndices(chartSizesIS, &chartSize)); 2084 PetscCall(ISRestoreIndices(ownersIS, &owners)); 2085 PetscCall(ISRestoreIndices(gpointsIS, &gpoints)); 2086 PetscCall(ISDestroy(&chartSizesIS)); 2087 PetscCall(ISDestroy(&ownersIS)); 2088 PetscCall(ISDestroy(&gpointsIS)); 2089 /* Record that overlap has been manually created. */ 2090 /* This is to pass `DMPlexCheckPointSF()`, which checks that */ 2091 /* pointSF does not contain cells in the leaves if overlap = 0. */ 2092 PetscCall(DMPlexSetOverlap_Plex(*distdm, NULL, DMPLEX_OVERLAP_MANUAL)); 2093 PetscCall(DMPlexDistributeSetDefault(*distdm, PETSC_FALSE)); 2094 PetscCall(DMPlexReorderSetDefault(*distdm, DM_REORDER_DEFAULT_FALSE)); 2095 PetscCall(PetscLogEventEnd(DMPLEX_DistributionLoad, viewer, 0, 0, 0)); 2096 PetscFunctionReturn(PETSC_SUCCESS); 2097 } 2098 2099 // Serial load of topology 2100 static PetscErrorCode DMPlexTopologyLoad_HDF5_Legacy_Private(DM dm, PetscViewer viewer, PetscSF *sf) 2101 { 2102 MPI_Comm comm; 2103 const char *pointsName, *coneSizesName, *conesName, *orientationsName; 2104 IS pointsIS, coneSizesIS, conesIS, orientationsIS; 2105 const PetscInt *points, *coneSizes, *cones, *orientations; 2106 PetscInt *cone, *ornt; 2107 PetscInt dim, N, Np, pEnd, p, q, maxConeSize = 0, c; 2108 PetscMPIInt size, rank; 2109 2110 PetscFunctionBegin; 2111 pointsName = "order"; 2112 coneSizesName = "cones"; 2113 conesName = "cells"; 2114 orientationsName = "orientation"; 2115 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2116 PetscCallMPI(MPI_Comm_size(comm, &size)); 2117 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2118 PetscCall(ISCreate(comm, &pointsIS)); 2119 PetscCall(PetscObjectSetName((PetscObject)pointsIS, pointsName)); 2120 PetscCall(ISCreate(comm, &coneSizesIS)); 2121 PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName)); 2122 PetscCall(ISCreate(comm, &conesIS)); 2123 PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName)); 2124 PetscCall(ISCreate(comm, &orientationsIS)); 2125 PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName)); 2126 PetscCall(PetscViewerHDF5ReadObjectAttribute(viewer, (PetscObject)conesIS, "cell_dim", PETSC_INT, NULL, &dim)); 2127 PetscCall(DMSetDimension(dm, dim)); 2128 { 2129 /* Force serial load */ 2130 PetscCall(PetscInfo(dm, "Loading DM %s in serial\n", dm->hdr.name)); 2131 PetscCall(PetscViewerHDF5ReadSizes(viewer, pointsName, NULL, &Np)); 2132 PetscCall(PetscLayoutSetLocalSize(pointsIS->map, rank == 0 ? Np : 0)); 2133 PetscCall(PetscLayoutSetSize(pointsIS->map, Np)); 2134 pEnd = rank == 0 ? Np : 0; 2135 PetscCall(PetscViewerHDF5ReadSizes(viewer, coneSizesName, NULL, &Np)); 2136 PetscCall(PetscLayoutSetLocalSize(coneSizesIS->map, rank == 0 ? Np : 0)); 2137 PetscCall(PetscLayoutSetSize(coneSizesIS->map, Np)); 2138 PetscCall(PetscViewerHDF5ReadSizes(viewer, conesName, NULL, &N)); 2139 PetscCall(PetscLayoutSetLocalSize(conesIS->map, rank == 0 ? N : 0)); 2140 PetscCall(PetscLayoutSetSize(conesIS->map, N)); 2141 PetscCall(PetscViewerHDF5ReadSizes(viewer, orientationsName, NULL, &N)); 2142 PetscCall(PetscLayoutSetLocalSize(orientationsIS->map, rank == 0 ? N : 0)); 2143 PetscCall(PetscLayoutSetSize(orientationsIS->map, N)); 2144 } 2145 PetscCall(ISLoad(pointsIS, viewer)); 2146 PetscCall(ISLoad(coneSizesIS, viewer)); 2147 PetscCall(ISLoad(conesIS, viewer)); 2148 PetscCall(ISLoad(orientationsIS, viewer)); 2149 /* Create Plex */ 2150 PetscCall(DMPlexSetChart(dm, 0, pEnd)); 2151 PetscCall(ISGetIndices(pointsIS, &points)); 2152 PetscCall(ISGetIndices(coneSizesIS, &coneSizes)); 2153 for (p = 0; p < pEnd; ++p) { 2154 PetscCall(DMPlexSetConeSize(dm, points[p], coneSizes[p])); 2155 maxConeSize = PetscMax(maxConeSize, coneSizes[p]); 2156 } 2157 PetscCall(DMSetUp(dm)); 2158 PetscCall(ISGetIndices(conesIS, &cones)); 2159 PetscCall(ISGetIndices(orientationsIS, &orientations)); 2160 PetscCall(PetscMalloc2(maxConeSize, &cone, maxConeSize, &ornt)); 2161 for (p = 0, q = 0; p < pEnd; ++p) { 2162 for (c = 0; c < coneSizes[p]; ++c, ++q) { 2163 cone[c] = cones[q]; 2164 ornt[c] = orientations[q]; 2165 } 2166 PetscCall(DMPlexSetCone(dm, points[p], cone)); 2167 PetscCall(DMPlexSetConeOrientation(dm, points[p], ornt)); 2168 } 2169 PetscCall(PetscFree2(cone, ornt)); 2170 /* Create global section migration SF */ 2171 if (sf) { 2172 PetscLayout layout; 2173 PetscInt *globalIndices; 2174 2175 PetscCall(PetscMalloc1(pEnd, &globalIndices)); 2176 /* plex point == globalPointNumber in this case */ 2177 for (p = 0; p < pEnd; ++p) globalIndices[p] = p; 2178 PetscCall(PetscLayoutCreate(comm, &layout)); 2179 PetscCall(PetscLayoutSetSize(layout, Np)); 2180 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 2181 PetscCall(PetscLayoutSetUp(layout)); 2182 PetscCall(PetscSFCreate(comm, sf)); 2183 PetscCall(PetscSFSetFromOptions(*sf)); 2184 PetscCall(PetscSFSetGraphLayout(*sf, layout, pEnd, NULL, PETSC_OWN_POINTER, globalIndices)); 2185 PetscCall(PetscLayoutDestroy(&layout)); 2186 PetscCall(PetscFree(globalIndices)); 2187 } 2188 /* Clean-up */ 2189 PetscCall(ISRestoreIndices(pointsIS, &points)); 2190 PetscCall(ISRestoreIndices(coneSizesIS, &coneSizes)); 2191 PetscCall(ISRestoreIndices(conesIS, &cones)); 2192 PetscCall(ISRestoreIndices(orientationsIS, &orientations)); 2193 PetscCall(ISDestroy(&pointsIS)); 2194 PetscCall(ISDestroy(&coneSizesIS)); 2195 PetscCall(ISDestroy(&conesIS)); 2196 PetscCall(ISDestroy(&orientationsIS)); 2197 /* Fill in the rest of the topology structure */ 2198 PetscCall(DMPlexSymmetrize(dm)); 2199 PetscCall(DMPlexStratify(dm)); 2200 PetscFunctionReturn(PETSC_SUCCESS); 2201 } 2202 2203 /* Representation of two DMPlex strata in 0-based global numbering */ 2204 struct _n_PlexLayer { 2205 PetscInt d; 2206 IS conesIS, orientationsIS; 2207 PetscSection coneSizesSection; 2208 PetscLayout vertexLayout; 2209 PetscSF overlapSF, l2gSF; //TODO maybe confusing names (in DMPlex in general) 2210 PetscInt offset, conesOffset, leafOffset; 2211 }; 2212 typedef struct _n_PlexLayer *PlexLayer; 2213 2214 static PetscErrorCode PlexLayerDestroy(PlexLayer *layer) 2215 { 2216 PetscFunctionBegin; 2217 if (!*layer) PetscFunctionReturn(PETSC_SUCCESS); 2218 PetscCall(PetscSectionDestroy(&(*layer)->coneSizesSection)); 2219 PetscCall(ISDestroy(&(*layer)->conesIS)); 2220 PetscCall(ISDestroy(&(*layer)->orientationsIS)); 2221 PetscCall(PetscSFDestroy(&(*layer)->overlapSF)); 2222 PetscCall(PetscSFDestroy(&(*layer)->l2gSF)); 2223 PetscCall(PetscLayoutDestroy(&(*layer)->vertexLayout)); 2224 PetscCall(PetscFree(*layer)); 2225 PetscFunctionReturn(PETSC_SUCCESS); 2226 } 2227 2228 static PetscErrorCode PlexLayerCreate_Private(PlexLayer *layer) 2229 { 2230 PetscFunctionBegin; 2231 PetscCall(PetscNew(layer)); 2232 (*layer)->d = -1; 2233 (*layer)->offset = -1; 2234 (*layer)->conesOffset = -1; 2235 (*layer)->leafOffset = -1; 2236 PetscFunctionReturn(PETSC_SUCCESS); 2237 } 2238 2239 // Parallel load of a depth stratum 2240 static PetscErrorCode PlexLayerLoad_Private(PlexLayer layer, PetscViewer viewer, PetscInt d, PetscLayout pointsLayout) 2241 { 2242 char path[128]; 2243 MPI_Comm comm; 2244 const char *coneSizesName, *conesName, *orientationsName; 2245 IS coneSizesIS, conesIS, orientationsIS; 2246 PetscSection coneSizesSection; 2247 PetscLayout vertexLayout = NULL; 2248 PetscInt s; 2249 2250 PetscFunctionBegin; 2251 coneSizesName = "cone_sizes"; 2252 conesName = "cones"; 2253 orientationsName = "orientations"; 2254 PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm)); 2255 2256 /* query size of next lower depth stratum (next lower dimension) */ 2257 if (d > 0) { 2258 PetscInt NVertices; 2259 2260 PetscCall(PetscSNPrintf(path, sizeof(path), "%" PetscInt_FMT "/%s", d - 1, coneSizesName)); 2261 PetscCall(PetscViewerHDF5ReadSizes(viewer, path, NULL, &NVertices)); 2262 PetscCall(PetscLayoutCreate(comm, &vertexLayout)); 2263 PetscCall(PetscLayoutSetSize(vertexLayout, NVertices)); 2264 PetscCall(PetscLayoutSetUp(vertexLayout)); 2265 } 2266 2267 PetscCall(PetscSNPrintf(path, sizeof(path), "%" PetscInt_FMT, d)); 2268 PetscCall(PetscViewerHDF5PushGroup(viewer, path)); 2269 2270 /* create coneSizesSection from stored IS coneSizes */ 2271 { 2272 const PetscInt *coneSizes; 2273 2274 PetscCall(ISCreate(comm, &coneSizesIS)); 2275 PetscCall(PetscObjectSetName((PetscObject)coneSizesIS, coneSizesName)); 2276 if (pointsLayout) PetscCall(ISSetLayout(coneSizesIS, pointsLayout)); 2277 PetscCall(ISLoad(coneSizesIS, viewer)); 2278 if (!pointsLayout) PetscCall(ISGetLayout(coneSizesIS, &pointsLayout)); 2279 PetscCall(ISGetIndices(coneSizesIS, &coneSizes)); 2280 PetscCall(PetscSectionCreate(comm, &coneSizesSection)); 2281 //TODO different start ? 2282 PetscCall(PetscSectionSetChart(coneSizesSection, 0, pointsLayout->n)); 2283 for (s = 0; s < pointsLayout->n; ++s) PetscCall(PetscSectionSetDof(coneSizesSection, s, coneSizes[s])); 2284 PetscCall(PetscSectionSetUp(coneSizesSection)); 2285 PetscCall(ISRestoreIndices(coneSizesIS, &coneSizes)); 2286 { 2287 PetscLayout tmp = NULL; 2288 2289 /* We need to keep the layout until the end of function */ 2290 PetscCall(PetscLayoutReference((PetscLayout)pointsLayout, &tmp)); 2291 } 2292 PetscCall(ISDestroy(&coneSizesIS)); 2293 } 2294 2295 /* use value layout of coneSizesSection as layout of cones and orientations */ 2296 { 2297 PetscLayout conesLayout; 2298 2299 PetscCall(PetscSectionGetValueLayout(comm, coneSizesSection, &conesLayout)); 2300 PetscCall(ISCreate(comm, &conesIS)); 2301 PetscCall(ISCreate(comm, &orientationsIS)); 2302 PetscCall(PetscObjectSetName((PetscObject)conesIS, conesName)); 2303 PetscCall(PetscObjectSetName((PetscObject)orientationsIS, orientationsName)); 2304 PetscCall(PetscLayoutDuplicate(conesLayout, &conesIS->map)); 2305 PetscCall(PetscLayoutDuplicate(conesLayout, &orientationsIS->map)); 2306 PetscCall(ISLoad(conesIS, viewer)); 2307 PetscCall(ISLoad(orientationsIS, viewer)); 2308 PetscCall(PetscLayoutDestroy(&conesLayout)); 2309 } 2310 2311 /* check assertion that layout of points is the same as point layout of coneSizesSection */ 2312 { 2313 PetscLayout pointsLayout0; 2314 PetscBool flg; 2315 2316 PetscCall(PetscSectionGetPointLayout(comm, coneSizesSection, &pointsLayout0)); 2317 PetscCall(PetscLayoutCompare(pointsLayout, pointsLayout0, &flg)); 2318 PetscCheck(flg, comm, PETSC_ERR_PLIB, "points layout != coneSizesSection point layout"); 2319 PetscCall(PetscLayoutDestroy(&pointsLayout0)); 2320 } 2321 PetscCall(PetscViewerHDF5PopGroup(viewer)); 2322 PetscCall(PetscLayoutDestroy(&pointsLayout)); 2323 2324 layer->d = d; 2325 layer->conesIS = conesIS; 2326 layer->coneSizesSection = coneSizesSection; 2327 layer->orientationsIS = orientationsIS; 2328 layer->vertexLayout = vertexLayout; 2329 PetscFunctionReturn(PETSC_SUCCESS); 2330 } 2331 2332 static PetscErrorCode PlexLayerDistribute_Private(PlexLayer layer, PetscSF cellLocalToGlobalSF) 2333 { 2334 IS newConesIS, newOrientationsIS; 2335 PetscSection newConeSizesSection; 2336 MPI_Comm comm; 2337 2338 PetscFunctionBegin; 2339 PetscCall(PetscObjectGetComm((PetscObject)cellLocalToGlobalSF, &comm)); 2340 PetscCall(PetscSectionCreate(comm, &newConeSizesSection)); 2341 //TODO rename to something like ISDistribute() with optional PetscSection argument 2342 PetscCall(DMPlexDistributeFieldIS(NULL, cellLocalToGlobalSF, layer->coneSizesSection, layer->conesIS, newConeSizesSection, &newConesIS)); 2343 PetscCall(DMPlexDistributeFieldIS(NULL, cellLocalToGlobalSF, layer->coneSizesSection, layer->orientationsIS, newConeSizesSection, &newOrientationsIS)); 2344 2345 PetscCall(PetscObjectSetName((PetscObject)newConeSizesSection, ((PetscObject)layer->coneSizesSection)->name)); 2346 PetscCall(PetscObjectSetName((PetscObject)newConesIS, ((PetscObject)layer->conesIS)->name)); 2347 PetscCall(PetscObjectSetName((PetscObject)newOrientationsIS, ((PetscObject)layer->orientationsIS)->name)); 2348 PetscCall(PetscSectionDestroy(&layer->coneSizesSection)); 2349 PetscCall(ISDestroy(&layer->conesIS)); 2350 PetscCall(ISDestroy(&layer->orientationsIS)); 2351 layer->coneSizesSection = newConeSizesSection; 2352 layer->conesIS = newConesIS; 2353 layer->orientationsIS = newOrientationsIS; 2354 PetscFunctionReturn(PETSC_SUCCESS); 2355 } 2356 2357 //TODO share code with DMPlexBuildFromCellListParallel() 2358 #include <petsc/private/hashseti.h> 2359 static PetscErrorCode PlexLayerCreateSFs_Private(PlexLayer layer, PetscSF *vertexOverlapSF, PetscSF *sfXC) 2360 { 2361 PetscLayout vertexLayout = layer->vertexLayout; 2362 PetscSection coneSection = layer->coneSizesSection; 2363 IS cellVertexData = layer->conesIS; 2364 IS coneOrientations = layer->orientationsIS; 2365 PetscSF vl2gSF, vOverlapSF; 2366 PetscInt *verticesAdj; 2367 PetscInt i, n, numVerticesAdj; 2368 const PetscInt *cvd, *co = NULL; 2369 MPI_Comm comm; 2370 2371 PetscFunctionBegin; 2372 PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm)); 2373 PetscCall(PetscSectionGetStorageSize(coneSection, &n)); 2374 { 2375 PetscInt n0; 2376 2377 PetscCall(ISGetLocalSize(cellVertexData, &n0)); 2378 PetscCheck(n == n0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local size of IS cellVertexData = %" PetscInt_FMT " != %" PetscInt_FMT " = storage size of PetscSection coneSection", n0, n); 2379 PetscCall(ISGetIndices(cellVertexData, &cvd)); 2380 } 2381 if (coneOrientations) { 2382 PetscInt n0; 2383 2384 PetscCall(ISGetLocalSize(coneOrientations, &n0)); 2385 PetscCheck(n == n0, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local size of IS coneOrientations = %" PetscInt_FMT " != %" PetscInt_FMT " = storage size of PetscSection coneSection", n0, n); 2386 PetscCall(ISGetIndices(coneOrientations, &co)); 2387 } 2388 /* Get/check global number of vertices */ 2389 { 2390 PetscInt NVerticesInCells = PETSC_INT_MIN; 2391 2392 /* NVerticesInCells = max(cellVertexData) + 1 */ 2393 for (i = 0; i < n; i++) 2394 if (cvd[i] > NVerticesInCells) NVerticesInCells = cvd[i]; 2395 ++NVerticesInCells; 2396 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, comm)); 2397 2398 if (vertexLayout->n == PETSC_DECIDE && vertexLayout->N == PETSC_DECIDE) vertexLayout->N = NVerticesInCells; 2399 else 2400 PetscCheck(vertexLayout->N == PETSC_DECIDE || vertexLayout->N >= NVerticesInCells, comm, PETSC_ERR_ARG_SIZ, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of unique vertices in the cell-vertex dataset %" PetscInt_FMT, 2401 vertexLayout->N, NVerticesInCells); 2402 PetscCall(PetscLayoutSetUp(vertexLayout)); 2403 } 2404 /* Find locally unique vertices in cellVertexData */ 2405 { 2406 PetscHSetI vhash; 2407 PetscInt off = 0; 2408 2409 PetscCall(PetscHSetICreate(&vhash)); 2410 for (i = 0; i < n; ++i) PetscCall(PetscHSetIAdd(vhash, cvd[i])); 2411 PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj)); 2412 PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj)); 2413 PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj)); 2414 PetscAssert(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Assertion failed: off == numVerticesAdj (%" PetscInt_FMT " != %" PetscInt_FMT ")", off, numVerticesAdj); 2415 PetscCall(PetscHSetIDestroy(&vhash)); 2416 } 2417 /* We must sort vertices to preserve numbering */ 2418 PetscCall(PetscSortInt(numVerticesAdj, verticesAdj)); 2419 /* Connect locally unique vertices with star forest */ 2420 PetscCall(PetscSFCreateByMatchingIndices(vertexLayout, numVerticesAdj, verticesAdj, NULL, 0, numVerticesAdj, verticesAdj, NULL, 0, &vl2gSF, &vOverlapSF)); 2421 PetscCall(PetscObjectSetName((PetscObject)vOverlapSF, "overlapSF")); 2422 PetscCall(PetscObjectSetName((PetscObject)vl2gSF, "localToGlobalSF")); 2423 2424 PetscCall(PetscFree(verticesAdj)); 2425 *vertexOverlapSF = vOverlapSF; 2426 *sfXC = vl2gSF; 2427 PetscFunctionReturn(PETSC_SUCCESS); 2428 } 2429 2430 static PetscErrorCode PlexLayerCreateCellSFs_Private(PlexLayer layer, PetscSF *cellOverlapSF, PetscSF *cellLocalToGlobalSF) 2431 { 2432 PetscSection coneSection = layer->coneSizesSection; 2433 PetscInt nCells; 2434 MPI_Comm comm; 2435 2436 PetscFunctionBegin; 2437 PetscCall(PetscObjectGetComm((PetscObject)coneSection, &comm)); 2438 { 2439 PetscInt cStart; 2440 2441 PetscCall(PetscSectionGetChart(coneSection, &cStart, &nCells)); 2442 PetscCheck(cStart == 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "coneSection must start at 0"); 2443 } 2444 /* Create overlapSF as empty SF with the right number of roots */ 2445 PetscCall(PetscSFCreate(comm, cellOverlapSF)); 2446 PetscCall(PetscSFSetGraph(*cellOverlapSF, nCells, 0, NULL, PETSC_USE_POINTER, NULL, PETSC_USE_POINTER)); 2447 PetscCall(PetscSFSetUp(*cellOverlapSF)); 2448 /* Create localToGlobalSF as identity mapping */ 2449 { 2450 PetscLayout map; 2451 2452 PetscCall(PetscLayoutCreateFromSizes(comm, nCells, PETSC_DECIDE, 1, &map)); 2453 PetscCall(PetscSFCreateFromLayouts(map, map, cellLocalToGlobalSF)); 2454 PetscCall(PetscSFSetUp(*cellLocalToGlobalSF)); 2455 PetscCall(PetscLayoutDestroy(&map)); 2456 } 2457 PetscFunctionReturn(PETSC_SUCCESS); 2458 } 2459 2460 static PetscErrorCode DMPlexTopologyBuildFromLayers_Private(DM dm, PetscInt depth, PlexLayer *layers, IS strataPermutation) 2461 { 2462 const PetscInt *permArr; 2463 PetscInt d, nPoints; 2464 MPI_Comm comm; 2465 2466 PetscFunctionBegin; 2467 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2468 PetscCall(ISGetIndices(strataPermutation, &permArr)); 2469 2470 /* Count points, strata offsets and cones offsets (taking strataPermutation into account) */ 2471 { 2472 PetscInt stratumOffset = 0; 2473 PetscInt conesOffset = 0; 2474 2475 for (d = 0; d <= depth; d++) { 2476 const PetscInt e = permArr[d]; 2477 const PlexLayer l = layers[e]; 2478 PetscInt lo, n, size; 2479 2480 PetscCall(PetscSectionGetChart(l->coneSizesSection, &lo, &n)); 2481 PetscCall(PetscSectionGetStorageSize(l->coneSizesSection, &size)); 2482 PetscCheck(lo == 0, comm, PETSC_ERR_PLIB, "starting point should be 0 in coneSizesSection %" PetscInt_FMT, d); 2483 l->offset = stratumOffset; 2484 l->conesOffset = conesOffset; 2485 stratumOffset += n; 2486 conesOffset += size; 2487 } 2488 nPoints = stratumOffset; 2489 } 2490 2491 /* Set interval for all plex points */ 2492 //TODO we should store starting point of plex 2493 PetscCall(DMPlexSetChart(dm, 0, nPoints)); 2494 2495 /* Set up plex coneSection from layer coneSections */ 2496 { 2497 PetscSection coneSection; 2498 2499 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 2500 for (d = 0; d <= depth; d++) { 2501 const PlexLayer l = layers[d]; 2502 PetscInt n, q; 2503 2504 PetscCall(PetscSectionGetChart(l->coneSizesSection, NULL, &n)); 2505 for (q = 0; q < n; q++) { 2506 const PetscInt p = l->offset + q; 2507 PetscInt coneSize; 2508 2509 PetscCall(PetscSectionGetDof(l->coneSizesSection, q, &coneSize)); 2510 PetscCall(PetscSectionSetDof(coneSection, p, coneSize)); 2511 } 2512 } 2513 } 2514 //TODO this is terrible, DMSetUp_Plex() should be DMPlexSetUpSections() or so 2515 PetscCall(DMSetUp(dm)); 2516 2517 /* Renumber cones points from layer-global numbering to plex-local numbering */ 2518 { 2519 PetscInt *cones, *ornts; 2520 2521 PetscCall(DMPlexGetCones(dm, &cones)); 2522 PetscCall(DMPlexGetConeOrientations(dm, &ornts)); 2523 for (d = 1; d <= depth; d++) { 2524 const PlexLayer l = layers[d]; 2525 PetscInt i, lConesSize; 2526 PetscInt *lCones; 2527 const PetscInt *lOrnts; 2528 PetscInt *pCones = &cones[l->conesOffset]; 2529 PetscInt *pOrnts = &ornts[l->conesOffset]; 2530 2531 PetscCall(PetscSectionGetStorageSize(l->coneSizesSection, &lConesSize)); 2532 /* Get cones in local plex numbering */ 2533 { 2534 ISLocalToGlobalMapping l2g; 2535 PetscLayout vertexLayout = l->vertexLayout; 2536 PetscSF vertexSF = layers[d - 1]->l2gSF; /* vertices of this layer are cells of previous layer */ 2537 const PetscInt *gCones; 2538 PetscInt lConesSize0; 2539 2540 PetscCall(ISGetLocalSize(l->conesIS, &lConesSize0)); 2541 PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "layer %" PetscInt_FMT " size(conesIS) = %" PetscInt_FMT " != %" PetscInt_FMT " = storageSize(coneSizesSection)", d, lConesSize0, lConesSize); 2542 PetscCall(ISGetLocalSize(l->orientationsIS, &lConesSize0)); 2543 PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "layer %" PetscInt_FMT " size(orientationsIS) = %" PetscInt_FMT " != %" PetscInt_FMT " = storageSize(coneSizesSection)", d, lConesSize0, lConesSize); 2544 2545 PetscCall(PetscMalloc1(lConesSize, &lCones)); 2546 PetscCall(ISGetIndices(l->conesIS, &gCones)); 2547 PetscCall(ISLocalToGlobalMappingCreateSF(vertexSF, vertexLayout->rstart, &l2g)); 2548 PetscCall(ISGlobalToLocalMappingApply(l2g, IS_GTOLM_MASK, lConesSize, gCones, &lConesSize0, lCones)); 2549 PetscCheck(lConesSize0 == lConesSize, comm, PETSC_ERR_PLIB, "global to local does not cover all indices (%" PetscInt_FMT " of %" PetscInt_FMT ")", lConesSize0, lConesSize); 2550 PetscCall(ISLocalToGlobalMappingDestroy(&l2g)); 2551 PetscCall(ISRestoreIndices(l->conesIS, &gCones)); 2552 } 2553 PetscCall(ISGetIndices(l->orientationsIS, &lOrnts)); 2554 /* Set cones, need to add stratum offset */ 2555 for (i = 0; i < lConesSize; i++) { 2556 pCones[i] = lCones[i] + layers[d - 1]->offset; /* cone points of current layer are points of previous layer */ 2557 pOrnts[i] = lOrnts[i]; 2558 } 2559 PetscCall(PetscFree(lCones)); 2560 PetscCall(ISRestoreIndices(l->orientationsIS, &lOrnts)); 2561 } 2562 } 2563 PetscCall(DMPlexSymmetrize(dm)); 2564 PetscCall(DMPlexStratify(dm)); 2565 PetscCall(ISRestoreIndices(strataPermutation, &permArr)); 2566 PetscFunctionReturn(PETSC_SUCCESS); 2567 } 2568 2569 static PetscErrorCode PlexLayerConcatenateSFs_Private(MPI_Comm comm, PetscInt depth, PlexLayer layers[], IS strataPermutation, PetscSF *overlapSF, PetscSF *l2gSF) 2570 { 2571 PetscInt d; 2572 PetscSF *osfs, *lsfs; 2573 PetscInt *leafOffsets; 2574 const PetscInt *permArr; 2575 2576 PetscFunctionBegin; 2577 PetscCall(ISGetIndices(strataPermutation, &permArr)); 2578 PetscCall(PetscCalloc3(depth + 1, &osfs, depth + 1, &lsfs, depth + 1, &leafOffsets)); 2579 for (d = 0; d <= depth; d++) { 2580 const PetscInt e = permArr[d]; 2581 2582 PetscAssert(e == layers[e]->d, PETSC_COMM_SELF, PETSC_ERR_PLIB, "assertion: e == layers[e]->d"); 2583 osfs[d] = layers[e]->overlapSF; 2584 lsfs[d] = layers[e]->l2gSF; 2585 leafOffsets[d] = layers[e]->offset; 2586 } 2587 PetscCall(PetscSFConcatenate(comm, depth + 1, osfs, PETSCSF_CONCATENATE_ROOTMODE_LOCAL, leafOffsets, overlapSF)); 2588 PetscCall(PetscSFConcatenate(comm, depth + 1, lsfs, PETSCSF_CONCATENATE_ROOTMODE_GLOBAL, leafOffsets, l2gSF)); 2589 PetscCall(PetscFree3(osfs, lsfs, leafOffsets)); 2590 PetscCall(ISRestoreIndices(strataPermutation, &permArr)); 2591 PetscFunctionReturn(PETSC_SUCCESS); 2592 } 2593 2594 // Parallel load of topology 2595 static PetscErrorCode DMPlexTopologyLoad_HDF5_Private(DM dm, PetscViewer viewer, PetscSF *sfXC) 2596 { 2597 PlexLayer *layers; 2598 IS strataPermutation; 2599 PetscLayout pointsLayout; 2600 PetscInt depth; 2601 PetscInt d; 2602 MPI_Comm comm; 2603 2604 PetscFunctionBegin; 2605 { 2606 PetscInt dim; 2607 2608 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "depth", PETSC_INT, NULL, &depth)); 2609 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "cell_dim", PETSC_INT, NULL, &dim)); 2610 PetscCall(DMSetDimension(dm, dim)); 2611 } 2612 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2613 2614 PetscCall(PetscInfo(dm, "Loading DM %s in parallel\n", dm->hdr.name)); 2615 { 2616 IS spOnComm; 2617 2618 PetscCall(ISCreate(comm, &spOnComm)); 2619 PetscCall(PetscObjectSetName((PetscObject)spOnComm, "permutation")); 2620 PetscCall(ISLoad(spOnComm, viewer)); 2621 /* have the same serial IS on every rank */ 2622 PetscCall(ISAllGather(spOnComm, &strataPermutation)); 2623 PetscCall(PetscObjectSetName((PetscObject)strataPermutation, ((PetscObject)spOnComm)->name)); 2624 PetscCall(ISDestroy(&spOnComm)); 2625 } 2626 2627 /* Create layers, load raw data for each layer */ 2628 PetscCall(PetscViewerHDF5PushGroup(viewer, "strata")); 2629 PetscCall(PetscMalloc1(depth + 1, &layers)); 2630 for (d = depth, pointsLayout = NULL; d >= 0; pointsLayout = layers[d]->vertexLayout, d--) { 2631 PetscCall(PlexLayerCreate_Private(&layers[d])); 2632 PetscCall(PlexLayerLoad_Private(layers[d], viewer, d, pointsLayout)); 2633 } 2634 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* strata */ 2635 2636 for (d = depth; d >= 0; d--) { 2637 /* Redistribute cells and vertices for each applicable layer */ 2638 if (d < depth) PetscCall(PlexLayerDistribute_Private(layers[d], layers[d]->l2gSF)); 2639 /* Create vertex overlap SF and vertex localToGlobal SF for each applicable layer */ 2640 if (d > 0) PetscCall(PlexLayerCreateSFs_Private(layers[d], &layers[d - 1]->overlapSF, &layers[d - 1]->l2gSF)); 2641 } 2642 /* Build trivial SFs for the cell layer as well */ 2643 PetscCall(PlexLayerCreateCellSFs_Private(layers[depth], &layers[depth]->overlapSF, &layers[depth]->l2gSF)); 2644 2645 /* Build DMPlex topology from the layers */ 2646 PetscCall(DMPlexTopologyBuildFromLayers_Private(dm, depth, layers, strataPermutation)); 2647 2648 /* Build overall point SF alias overlap SF */ 2649 { 2650 PetscSF overlapSF; 2651 2652 PetscCall(PlexLayerConcatenateSFs_Private(comm, depth, layers, strataPermutation, &overlapSF, sfXC)); 2653 PetscCall(DMSetPointSF(dm, overlapSF)); 2654 PetscCall(PetscSFDestroy(&overlapSF)); 2655 } 2656 2657 for (d = depth; d >= 0; d--) PetscCall(PlexLayerDestroy(&layers[d])); 2658 PetscCall(PetscFree(layers)); 2659 PetscCall(ISDestroy(&strataPermutation)); 2660 PetscFunctionReturn(PETSC_SUCCESS); 2661 } 2662 2663 PetscErrorCode DMPlexTopologyLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF *sfXC) 2664 { 2665 DMPlexStorageVersion version; 2666 const char *topologydm_name; 2667 char group[PETSC_MAX_PATH_LEN]; 2668 PetscSF sfwork = NULL; 2669 2670 PetscFunctionBegin; 2671 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 2672 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version)); 2673 if (DMPlexStorageVersionGE(version, 2, 0, 0)) { 2674 PetscCall(PetscSNPrintf(group, sizeof(group), "topologies/%s", topologydm_name)); 2675 } else { 2676 PetscCall(PetscStrncpy(group, "/", sizeof(group))); 2677 } 2678 PetscCall(PetscViewerHDF5PushGroup(viewer, group)); 2679 2680 PetscCall(PetscViewerHDF5PushGroup(viewer, "topology")); 2681 if (version->major < 3) { 2682 PetscCall(DMPlexTopologyLoad_HDF5_Legacy_Private(dm, viewer, &sfwork)); 2683 } else { 2684 /* since DMPlexStorageVersion 3.0.0 */ 2685 PetscCall(DMPlexTopologyLoad_HDF5_Private(dm, viewer, &sfwork)); 2686 } 2687 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "topology" */ 2688 2689 if (DMPlexStorageVersionGE(version, 2, 0, 0)) { 2690 DM distdm; 2691 PetscSF distsf; 2692 const char *distribution_name; 2693 PetscBool exists; 2694 2695 PetscCall(DMPlexDistributionGetName(dm, &distribution_name)); 2696 /* this group is guaranteed to be present since DMPlexStorageVersion 2.1.0 */ 2697 PetscCall(PetscViewerHDF5PushGroup(viewer, "distributions")); 2698 PetscCall(PetscViewerHDF5HasGroup(viewer, NULL, &exists)); 2699 if (exists) { 2700 PetscCall(PetscViewerHDF5PushGroup(viewer, distribution_name)); 2701 PetscCall(DMPlexDistributionLoad_HDF5_Private(dm, viewer, sfwork, &distsf, &distdm)); 2702 if (distdm) { 2703 PetscCall(DMPlexReplace_Internal(dm, &distdm)); 2704 PetscCall(PetscSFDestroy(&sfwork)); 2705 sfwork = distsf; 2706 } 2707 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* distribution_name */ 2708 } 2709 PetscCall(PetscViewerHDF5PopGroup(viewer)); /* "distributions" */ 2710 } 2711 if (sfXC) { 2712 *sfXC = sfwork; 2713 } else { 2714 PetscCall(PetscSFDestroy(&sfwork)); 2715 } 2716 2717 PetscCall(PetscViewerHDF5PopGroup(viewer)); 2718 PetscFunctionReturn(PETSC_SUCCESS); 2719 } 2720 2721 /* If the file is old, it not only has different path to the coordinates, but */ 2722 /* does not contain coordinateDMs, so must fall back to the old implementation. */ 2723 static PetscErrorCode DMPlexCoordinatesLoad_HDF5_Legacy_Private(DM dm, PetscViewer viewer) 2724 { 2725 PetscSection coordSection; 2726 Vec coordinates; 2727 PetscReal lengthScale; 2728 PetscInt spatialDim, N, numVertices, vStart, vEnd, v; 2729 PetscMPIInt rank; 2730 2731 PetscFunctionBegin; 2732 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 2733 /* Read geometry */ 2734 PetscCall(PetscViewerHDF5PushGroup(viewer, "/geometry")); 2735 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates)); 2736 PetscCall(PetscObjectSetName((PetscObject)coordinates, "vertices")); 2737 { 2738 /* Force serial load */ 2739 PetscCall(PetscViewerHDF5ReadSizes(viewer, "vertices", &spatialDim, &N)); 2740 PetscCall(VecSetSizes(coordinates, rank == 0 ? N : 0, N)); 2741 PetscCall(VecSetBlockSize(coordinates, spatialDim)); 2742 } 2743 PetscCall(VecLoad(coordinates, viewer)); 2744 PetscCall(PetscViewerHDF5PopGroup(viewer)); 2745 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 2746 PetscCall(VecScale(coordinates, 1.0 / lengthScale)); 2747 PetscCall(VecGetLocalSize(coordinates, &numVertices)); 2748 PetscCall(VecGetBlockSize(coordinates, &spatialDim)); 2749 numVertices /= spatialDim; 2750 /* Create coordinates */ 2751 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 2752 PetscCheck(numVertices == vEnd - vStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of coordinates loaded %" PetscInt_FMT " does not match number of vertices %" PetscInt_FMT, numVertices, vEnd - vStart); 2753 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2754 PetscCall(PetscSectionSetNumFields(coordSection, 1)); 2755 PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spatialDim)); 2756 PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd)); 2757 for (v = vStart; v < vEnd; ++v) { 2758 PetscCall(PetscSectionSetDof(coordSection, v, spatialDim)); 2759 PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spatialDim)); 2760 } 2761 PetscCall(PetscSectionSetUp(coordSection)); 2762 PetscCall(DMSetCoordinates(dm, coordinates)); 2763 PetscCall(VecDestroy(&coordinates)); 2764 PetscFunctionReturn(PETSC_SUCCESS); 2765 } 2766 2767 PetscErrorCode DMPlexCoordinatesLoad_HDF5_Internal(DM dm, PetscViewer viewer, PetscSF sfXC) 2768 { 2769 DMPlexStorageVersion version; 2770 DM cdm; 2771 Vec coords; 2772 PetscInt blockSize; 2773 PetscReal lengthScale; 2774 PetscSF lsf; 2775 const char *topologydm_name; 2776 char *coordinatedm_name, *coordinates_name; 2777 2778 PetscFunctionBegin; 2779 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version)); 2780 if (!DMPlexStorageVersionGE(version, 2, 0, 0)) { 2781 PetscCall(DMPlexCoordinatesLoad_HDF5_Legacy_Private(dm, viewer)); 2782 PetscFunctionReturn(PETSC_SUCCESS); 2783 } 2784 /* else: since DMPlexStorageVersion 2.0.0 */ 2785 PetscCheck(sfXC, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "PetscSF must be given for parallel load"); 2786 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 2787 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 2788 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 2789 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "coordinateDMName", PETSC_STRING, NULL, &coordinatedm_name)); 2790 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "coordinatesName", PETSC_STRING, NULL, &coordinates_name)); 2791 PetscCall(PetscViewerHDF5PopGroup(viewer)); 2792 PetscCall(PetscViewerHDF5PopGroup(viewer)); 2793 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2794 PetscCall(PetscObjectSetName((PetscObject)cdm, coordinatedm_name)); 2795 PetscCall(PetscFree(coordinatedm_name)); 2796 /* lsf: on-disk data -> in-memory local vector associated with cdm's local section */ 2797 PetscCall(DMPlexSectionLoad(dm, viewer, cdm, sfXC, NULL, &lsf)); 2798 PetscCall(DMCreateLocalVector(cdm, &coords)); 2799 PetscCall(PetscObjectSetName((PetscObject)coords, coordinates_name)); 2800 PetscCall(PetscFree(coordinates_name)); 2801 PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_NATIVE)); 2802 PetscCall(DMPlexLocalVectorLoad(dm, viewer, cdm, lsf, coords)); 2803 PetscCall(PetscViewerPopFormat(viewer)); 2804 PetscCall(DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale)); 2805 PetscCall(VecScale(coords, 1.0 / lengthScale)); 2806 PetscCall(DMSetCoordinatesLocal(dm, coords)); 2807 PetscCall(VecGetBlockSize(coords, &blockSize)); 2808 PetscCall(DMSetCoordinateDim(dm, blockSize)); 2809 PetscCall(VecDestroy(&coords)); 2810 PetscCall(PetscSFDestroy(&lsf)); 2811 PetscFunctionReturn(PETSC_SUCCESS); 2812 } 2813 2814 PetscErrorCode DMPlexLoad_HDF5_Internal(DM dm, PetscViewer viewer) 2815 { 2816 DMPlexStorageVersion version; 2817 2818 PetscFunctionBegin; 2819 PetscCall(PetscViewerHDF5GetDMPlexStorageVersionReading(viewer, &version)); 2820 PetscCall(PetscInfo(dm, "Loading DM %s storage version %d.%d.%d\n", dm->hdr.name, version->major, version->minor, version->subminor)); 2821 if (!DMPlexStorageVersionGE(version, 2, 0, 0)) { 2822 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, NULL)); 2823 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, NULL)); 2824 PetscCall(DMPlexCoordinatesLoad_HDF5_Legacy_Private(dm, viewer)); 2825 } else { 2826 PetscSF sfXC; 2827 2828 /* since DMPlexStorageVersion 2.0.0 */ 2829 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, &sfXC)); 2830 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, sfXC)); 2831 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, sfXC)); 2832 PetscCall(PetscSFDestroy(&sfXC)); 2833 } 2834 PetscFunctionReturn(PETSC_SUCCESS); 2835 } 2836 2837 static PetscErrorCode DMPlexSectionLoad_HDF5_Internal_CreateDataSF(PetscSection rootSection, PetscLayout layout, PetscInt globalOffsets[], PetscSection leafSection, PetscSF *sectionSF) 2838 { 2839 MPI_Comm comm; 2840 PetscInt pStart, pEnd, p, m; 2841 PetscInt *goffs, *ilocal; 2842 PetscBool rootIncludeConstraints, leafIncludeConstraints; 2843 2844 PetscFunctionBegin; 2845 PetscCall(PetscObjectGetComm((PetscObject)leafSection, &comm)); 2846 PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd)); 2847 PetscCall(PetscSectionGetIncludesConstraints(rootSection, &rootIncludeConstraints)); 2848 PetscCall(PetscSectionGetIncludesConstraints(leafSection, &leafIncludeConstraints)); 2849 if (rootIncludeConstraints && leafIncludeConstraints) PetscCall(PetscSectionGetStorageSize(leafSection, &m)); 2850 else PetscCall(PetscSectionGetConstrainedStorageSize(leafSection, &m)); 2851 PetscCall(PetscMalloc1(m, &ilocal)); 2852 PetscCall(PetscMalloc1(m, &goffs)); 2853 /* Currently, PetscSFDistributeSection() returns globalOffsets[] only */ 2854 /* for the top-level section (not for each field), so one must have */ 2855 /* rootSection->pointMajor == PETSC_TRUE. */ 2856 PetscCheck(rootSection->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering"); 2857 /* Currently, we also assume that leafSection->pointMajor == PETSC_TRUE. */ 2858 PetscCheck(leafSection->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering"); 2859 for (p = pStart, m = 0; p < pEnd; ++p) { 2860 PetscInt dof, cdof, i, j, off, goff; 2861 const PetscInt *cinds; 2862 2863 PetscCall(PetscSectionGetDof(leafSection, p, &dof)); 2864 if (dof < 0) continue; 2865 goff = globalOffsets[p - pStart]; 2866 PetscCall(PetscSectionGetOffset(leafSection, p, &off)); 2867 PetscCall(PetscSectionGetConstraintDof(leafSection, p, &cdof)); 2868 PetscCall(PetscSectionGetConstraintIndices(leafSection, p, &cinds)); 2869 for (i = 0, j = 0; i < dof; ++i) { 2870 PetscBool constrained = (PetscBool)(j < cdof && i == cinds[j]); 2871 2872 if (!constrained || (leafIncludeConstraints && rootIncludeConstraints)) { 2873 ilocal[m] = off++; 2874 goffs[m++] = goff++; 2875 } else if (leafIncludeConstraints && !rootIncludeConstraints) ++off; 2876 else if (!leafIncludeConstraints && rootIncludeConstraints) ++goff; 2877 if (constrained) ++j; 2878 } 2879 } 2880 PetscCall(PetscSFCreate(comm, sectionSF)); 2881 PetscCall(PetscSFSetFromOptions(*sectionSF)); 2882 PetscCall(PetscSFSetGraphLayout(*sectionSF, layout, m, ilocal, PETSC_OWN_POINTER, goffs)); 2883 PetscCall(PetscFree(goffs)); 2884 PetscFunctionReturn(PETSC_SUCCESS); 2885 } 2886 2887 PetscErrorCode DMPlexSectionLoad_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sfXB, PetscSF *gsf, PetscSF *lsf) 2888 { 2889 MPI_Comm comm; 2890 PetscMPIInt size, rank; 2891 const char *topologydm_name; 2892 const char *sectiondm_name; 2893 PetscSection sectionA, sectionB; 2894 PetscBool has; 2895 PetscInt nX, n, i; 2896 PetscSF sfAB; 2897 2898 PetscFunctionBegin; 2899 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2900 PetscCallMPI(MPI_Comm_size(comm, &size)); 2901 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2902 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 2903 PetscCall(PetscObjectGetName((PetscObject)sectiondm, §iondm_name)); 2904 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 2905 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 2906 PetscCall(PetscViewerHDF5PushGroup(viewer, "dms")); 2907 PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name)); 2908 /* A: on-disk points */ 2909 /* X: list of global point numbers, [0, NX) */ 2910 /* B: plex points */ 2911 /* Load raw section (sectionA) */ 2912 PetscCall(PetscSectionCreate(comm, §ionA)); 2913 PetscCall(PetscViewerHDF5HasGroup(viewer, "section", &has)); 2914 if (has) PetscCall(PetscSectionLoad(sectionA, viewer)); 2915 else { 2916 // TODO If section is missing, create the default affine section with dim dofs on each vertex. Use PetscSplitOwnership() to split vertices. 2917 // How do I know the total number of vertices? 2918 PetscInt dim, Nf = 1, Nv, nv = PETSC_DECIDE; 2919 2920 PetscCall(DMGetDimension(dm, &dim)); 2921 PetscCall(DMPlexGetDepthStratumGlobalSize(dm, 0, &Nv)); 2922 PetscCall(PetscSectionSetNumFields(sectionA, Nf)); 2923 PetscCall(PetscSectionSetFieldName(sectionA, 0, "Cartesian")); 2924 PetscCall(PetscSectionSetFieldComponents(sectionA, 0, dim)); 2925 for (PetscInt c = 0; c < dim; ++c) { 2926 char axis = 'X' + (char)c; 2927 2928 PetscCall(PetscSectionSetComponentName(sectionA, 0, c, &axis)); 2929 } 2930 PetscCall(PetscSplitOwnership(comm, &nv, &Nv)); 2931 PetscCall(PetscSectionSetChart(sectionA, 0, nv)); 2932 for (PetscInt p = 0; p < nv; ++p) { 2933 PetscCall(PetscSectionSetDof(sectionA, p, dim)); 2934 PetscCall(PetscSectionSetFieldDof(sectionA, p, 0, dim)); 2935 } 2936 PetscCall(PetscSectionSetUp(sectionA)); 2937 } 2938 PetscCall(PetscSectionGetChart(sectionA, NULL, &n)); 2939 /* Create sfAB: A -> B */ 2940 #if defined(PETSC_USE_DEBUG) 2941 { 2942 PetscInt N, N1; 2943 2944 PetscCall(PetscViewerHDF5ReadSizes(viewer, "order", NULL, &N1)); 2945 PetscCallMPI(MPIU_Allreduce(&n, &N, 1, MPIU_INT, MPI_SUM, comm)); 2946 PetscCheck(N1 == N, comm, PETSC_ERR_ARG_SIZ, "Mismatching sizes: on-disk order array size (%" PetscInt_FMT ") != number of loaded section points (%" PetscInt_FMT ")", N1, N); 2947 } 2948 #endif 2949 { 2950 IS orderIS; 2951 const PetscInt *gpoints; 2952 PetscSF sfXA, sfAX; 2953 PetscLayout layout; 2954 PetscSFNode *owners, *buffer; 2955 PetscInt nleaves; 2956 PetscInt *ilocal; 2957 PetscSFNode *iremote; 2958 2959 /* Create sfAX: A -> X */ 2960 PetscCall(ISCreate(comm, &orderIS)); 2961 PetscCall(PetscObjectSetName((PetscObject)orderIS, "order")); 2962 PetscCall(PetscLayoutSetLocalSize(orderIS->map, n)); 2963 PetscCall(ISLoad(orderIS, viewer)); 2964 PetscCall(PetscLayoutCreate(comm, &layout)); 2965 PetscCall(PetscSFGetGraph(sfXB, &nX, NULL, NULL, NULL)); 2966 PetscCall(PetscLayoutSetLocalSize(layout, nX)); 2967 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 2968 PetscCall(PetscLayoutSetUp(layout)); 2969 PetscCall(PetscSFCreate(comm, &sfXA)); 2970 PetscCall(ISGetIndices(orderIS, &gpoints)); 2971 PetscCall(PetscSFSetGraphLayout(sfXA, layout, n, NULL, PETSC_OWN_POINTER, gpoints)); 2972 PetscCall(ISRestoreIndices(orderIS, &gpoints)); 2973 PetscCall(ISDestroy(&orderIS)); 2974 PetscCall(PetscLayoutDestroy(&layout)); 2975 PetscCall(PetscMalloc1(n, &owners)); 2976 PetscCall(PetscMalloc1(nX, &buffer)); 2977 for (i = 0; i < n; ++i) { 2978 owners[i].rank = rank; 2979 owners[i].index = i; 2980 } 2981 for (i = 0; i < nX; ++i) { 2982 buffer[i].rank = -1; 2983 buffer[i].index = -1; 2984 } 2985 PetscCall(PetscSFReduceBegin(sfXA, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC)); 2986 PetscCall(PetscSFReduceEnd(sfXA, MPIU_SF_NODE, owners, buffer, MPI_MAXLOC)); 2987 PetscCall(PetscSFDestroy(&sfXA)); 2988 PetscCall(PetscFree(owners)); 2989 for (i = 0, nleaves = 0; i < nX; ++i) 2990 if (buffer[i].rank >= 0) nleaves++; 2991 PetscCall(PetscMalloc1(nleaves, &ilocal)); 2992 PetscCall(PetscMalloc1(nleaves, &iremote)); 2993 for (i = 0, nleaves = 0; i < nX; ++i) { 2994 if (buffer[i].rank >= 0) { 2995 ilocal[nleaves] = i; 2996 iremote[nleaves].rank = buffer[i].rank; 2997 iremote[nleaves].index = buffer[i].index; 2998 nleaves++; 2999 } 3000 } 3001 PetscCall(PetscFree(buffer)); 3002 PetscCall(PetscSFCreate(comm, &sfAX)); 3003 PetscCall(PetscSFSetFromOptions(sfAX)); 3004 PetscCall(PetscSFSetGraph(sfAX, n, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 3005 PetscCall(PetscSFCompose(sfAX, sfXB, &sfAB)); 3006 PetscCall(PetscSFDestroy(&sfAX)); 3007 } 3008 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3009 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3010 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3011 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3012 /* Create plex section (sectionB) */ 3013 PetscCall(DMGetLocalSection(sectiondm, §ionB)); 3014 if (lsf || gsf) { 3015 PetscLayout layout; 3016 PetscInt M, m; 3017 PetscInt *offsetsA; 3018 PetscBool includesConstraintsA; 3019 3020 PetscCall(PetscSFDistributeSection(sfAB, sectionA, &offsetsA, sectionB)); 3021 PetscCall(PetscSectionGetIncludesConstraints(sectionA, &includesConstraintsA)); 3022 if (includesConstraintsA) PetscCall(PetscSectionGetStorageSize(sectionA, &m)); 3023 else PetscCall(PetscSectionGetConstrainedStorageSize(sectionA, &m)); 3024 PetscCallMPI(MPIU_Allreduce(&m, &M, 1, MPIU_INT, MPI_SUM, comm)); 3025 PetscCall(PetscLayoutCreate(comm, &layout)); 3026 PetscCall(PetscLayoutSetSize(layout, M)); 3027 PetscCall(PetscLayoutSetUp(layout)); 3028 if (lsf) { 3029 PetscSF lsfABdata; 3030 3031 PetscCall(DMPlexSectionLoad_HDF5_Internal_CreateDataSF(sectionA, layout, offsetsA, sectionB, &lsfABdata)); 3032 *lsf = lsfABdata; 3033 } 3034 if (gsf) { 3035 PetscSection gsectionB, gsectionB1; 3036 PetscBool includesConstraintsB; 3037 PetscSF gsfABdata, pointsf; 3038 3039 PetscCall(DMGetGlobalSection(sectiondm, &gsectionB1)); 3040 PetscCall(PetscSectionGetIncludesConstraints(gsectionB1, &includesConstraintsB)); 3041 PetscCall(DMGetPointSF(sectiondm, &pointsf)); 3042 PetscCall(PetscSectionCreateGlobalSection(sectionB, pointsf, PETSC_TRUE, includesConstraintsB, PETSC_TRUE, &gsectionB)); 3043 PetscCall(DMPlexSectionLoad_HDF5_Internal_CreateDataSF(sectionA, layout, offsetsA, gsectionB, &gsfABdata)); 3044 PetscCall(PetscSectionDestroy(&gsectionB)); 3045 *gsf = gsfABdata; 3046 } 3047 PetscCall(PetscLayoutDestroy(&layout)); 3048 PetscCall(PetscFree(offsetsA)); 3049 } else { 3050 PetscCall(PetscSFDistributeSection(sfAB, sectionA, NULL, sectionB)); 3051 } 3052 PetscCall(PetscSFDestroy(&sfAB)); 3053 PetscCall(PetscSectionDestroy(§ionA)); 3054 PetscFunctionReturn(PETSC_SUCCESS); 3055 } 3056 3057 PetscErrorCode DMPlexVecLoad_HDF5_Internal(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 3058 { 3059 MPI_Comm comm; 3060 const char *topologydm_name; 3061 const char *sectiondm_name; 3062 const char *vec_name; 3063 Vec vecA; 3064 PetscInt mA, m, bs; 3065 const PetscInt *ilocal; 3066 const PetscScalar *src; 3067 PetscScalar *dest; 3068 3069 PetscFunctionBegin; 3070 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3071 PetscCall(DMPlexGetHDF5Name_Private(dm, &topologydm_name)); 3072 PetscCall(PetscObjectGetName((PetscObject)sectiondm, §iondm_name)); 3073 PetscCall(PetscObjectGetName((PetscObject)vec, &vec_name)); 3074 PetscCall(PetscViewerHDF5PushGroup(viewer, "topologies")); 3075 PetscCall(PetscViewerHDF5PushGroup(viewer, topologydm_name)); 3076 PetscCall(PetscViewerHDF5PushGroup(viewer, "dms")); 3077 PetscCall(PetscViewerHDF5PushGroup(viewer, sectiondm_name)); 3078 PetscCall(PetscViewerHDF5PushGroup(viewer, "vecs")); 3079 PetscCall(PetscViewerHDF5PushGroup(viewer, vec_name)); 3080 PetscCall(VecCreate(comm, &vecA)); 3081 PetscCall(PetscObjectSetName((PetscObject)vecA, vec_name)); 3082 PetscCall(PetscSFGetGraph(sf, &mA, &m, &ilocal, NULL)); 3083 /* Check consistency */ 3084 { 3085 PetscSF pointsf, pointsf1; 3086 PetscInt m1, i, j; 3087 3088 PetscCall(DMGetPointSF(dm, &pointsf)); 3089 PetscCall(DMGetPointSF(sectiondm, &pointsf1)); 3090 PetscCheck(pointsf1 == pointsf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatching point SFs for dm and sectiondm"); 3091 #if defined(PETSC_USE_DEBUG) 3092 { 3093 PetscInt MA, MA1; 3094 3095 PetscCallMPI(MPIU_Allreduce(&mA, &MA, 1, MPIU_INT, MPI_SUM, comm)); 3096 PetscCall(PetscViewerHDF5ReadSizes(viewer, vec_name, NULL, &MA1)); 3097 PetscCheck(MA1 == MA, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total SF root size (%" PetscInt_FMT ") != On-disk vector data size (%" PetscInt_FMT ")", MA, MA1); 3098 } 3099 #endif 3100 PetscCall(VecGetLocalSize(vec, &m1)); 3101 PetscCheck(m1 >= m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Target vector size (%" PetscInt_FMT ") < SF leaf size (%" PetscInt_FMT ")", m1, m); 3102 for (i = 0; i < m; ++i) { 3103 j = ilocal ? ilocal[i] : i; 3104 PetscCheck(j >= 0 && j < m1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Leaf's %" PetscInt_FMT "-th index, %" PetscInt_FMT ", not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", i, j, (PetscInt)0, m1); 3105 } 3106 } 3107 PetscCall(VecSetSizes(vecA, mA, PETSC_DECIDE)); 3108 PetscCall(VecLoad(vecA, viewer)); 3109 PetscCall(VecGetArrayRead(vecA, &src)); 3110 PetscCall(VecGetArray(vec, &dest)); 3111 PetscCall(PetscSFBcastBegin(sf, MPIU_SCALAR, src, dest, MPI_REPLACE)); 3112 PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, src, dest, MPI_REPLACE)); 3113 PetscCall(VecRestoreArray(vec, &dest)); 3114 PetscCall(VecRestoreArrayRead(vecA, &src)); 3115 PetscCall(VecDestroy(&vecA)); 3116 PetscCall(PetscViewerHDF5ReadAttribute(viewer, NULL, "blockSize", PETSC_INT, NULL, (void *)&bs)); 3117 PetscCall(VecSetBlockSize(vec, bs)); 3118 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3119 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3120 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3121 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3122 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3123 PetscCall(PetscViewerHDF5PopGroup(viewer)); 3124 PetscFunctionReturn(PETSC_SUCCESS); 3125 } 3126