1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/ 3 4 /*@C 5 DMPlexSetAdjacencyUser - Define adjacency in the mesh using a user-provided callback 6 7 Input Parameters: 8 + dm - The DM object 9 . user - The user callback, may be NULL (to clear the callback) 10 - ctx - context for callback evaluation, may be NULL 11 12 Level: advanced 13 14 Notes: 15 The caller of DMPlexGetAdjacency may need to arrange that a large enough array is available for the adjacency. 16 17 Any setting here overrides other configuration of DMPlex adjacency determination. 18 19 .seealso: `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexGetAdjacencyUser()` 20 @*/ 21 PetscErrorCode DMPlexSetAdjacencyUser(DM dm, PetscErrorCode (*user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void *ctx) 22 { 23 DM_Plex *mesh = (DM_Plex *)dm->data; 24 25 PetscFunctionBegin; 26 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 27 mesh->useradjacency = user; 28 mesh->useradjacencyctx = ctx; 29 PetscFunctionReturn(0); 30 } 31 32 /*@C 33 DMPlexGetAdjacencyUser - get the user-defined adjacency callback 34 35 Input Parameter: 36 . dm - The DM object 37 38 Output Parameters: 39 + user - The callback 40 - ctx - context for callback evaluation 41 42 Level: advanced 43 44 .seealso: `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexSetAdjacencyUser()` 45 @*/ 46 PetscErrorCode DMPlexGetAdjacencyUser(DM dm, PetscErrorCode (**user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void **ctx) 47 { 48 DM_Plex *mesh = (DM_Plex *)dm->data; 49 50 PetscFunctionBegin; 51 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 52 if (user) *user = mesh->useradjacency; 53 if (ctx) *ctx = mesh->useradjacencyctx; 54 PetscFunctionReturn(0); 55 } 56 57 /*@ 58 DMPlexSetAdjacencyUseAnchors - Define adjacency in the mesh using the point-to-point constraints. 59 60 Input Parameters: 61 + dm - The DM object 62 - useAnchors - Flag to use the constraints. If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place. 63 64 Level: intermediate 65 66 .seealso: `DMGetAdjacency()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()` 67 @*/ 68 PetscErrorCode DMPlexSetAdjacencyUseAnchors(DM dm, PetscBool useAnchors) 69 { 70 DM_Plex *mesh = (DM_Plex *)dm->data; 71 72 PetscFunctionBegin; 73 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 74 mesh->useAnchors = useAnchors; 75 PetscFunctionReturn(0); 76 } 77 78 /*@ 79 DMPlexGetAdjacencyUseAnchors - Query whether adjacency in the mesh uses the point-to-point constraints. 80 81 Input Parameter: 82 . dm - The DM object 83 84 Output Parameter: 85 . useAnchors - Flag to use the closure. If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place. 86 87 Level: intermediate 88 89 .seealso: `DMPlexSetAdjacencyUseAnchors()`, `DMSetAdjacency()`, `DMGetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()` 90 @*/ 91 PetscErrorCode DMPlexGetAdjacencyUseAnchors(DM dm, PetscBool *useAnchors) 92 { 93 DM_Plex *mesh = (DM_Plex *)dm->data; 94 95 PetscFunctionBegin; 96 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 97 PetscValidBoolPointer(useAnchors, 2); 98 *useAnchors = mesh->useAnchors; 99 PetscFunctionReturn(0); 100 } 101 102 static PetscErrorCode DMPlexGetAdjacency_Cone_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[]) 103 { 104 const PetscInt *cone = NULL; 105 PetscInt numAdj = 0, maxAdjSize = *adjSize, coneSize, c; 106 107 PetscFunctionBeginHot; 108 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 109 PetscCall(DMPlexGetCone(dm, p, &cone)); 110 for (c = 0; c <= coneSize; ++c) { 111 const PetscInt point = !c ? p : cone[c - 1]; 112 const PetscInt *support = NULL; 113 PetscInt supportSize, s, q; 114 115 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 116 PetscCall(DMPlexGetSupport(dm, point, &support)); 117 for (s = 0; s < supportSize; ++s) { 118 for (q = 0; q < numAdj || ((void)(adj[numAdj++] = support[s]), 0); ++q) { 119 if (support[s] == adj[q]) break; 120 } 121 PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize); 122 } 123 } 124 *adjSize = numAdj; 125 PetscFunctionReturn(0); 126 } 127 128 static PetscErrorCode DMPlexGetAdjacency_Support_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[]) 129 { 130 const PetscInt *support = NULL; 131 PetscInt numAdj = 0, maxAdjSize = *adjSize, supportSize, s; 132 133 PetscFunctionBeginHot; 134 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 135 PetscCall(DMPlexGetSupport(dm, p, &support)); 136 for (s = 0; s <= supportSize; ++s) { 137 const PetscInt point = !s ? p : support[s - 1]; 138 const PetscInt *cone = NULL; 139 PetscInt coneSize, c, q; 140 141 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 142 PetscCall(DMPlexGetCone(dm, point, &cone)); 143 for (c = 0; c < coneSize; ++c) { 144 for (q = 0; q < numAdj || ((void)(adj[numAdj++] = cone[c]), 0); ++q) { 145 if (cone[c] == adj[q]) break; 146 } 147 PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize); 148 } 149 } 150 *adjSize = numAdj; 151 PetscFunctionReturn(0); 152 } 153 154 static PetscErrorCode DMPlexGetAdjacency_Transitive_Internal(DM dm, PetscInt p, PetscBool useClosure, PetscInt *adjSize, PetscInt adj[]) 155 { 156 PetscInt *star = NULL; 157 PetscInt numAdj = 0, maxAdjSize = *adjSize, starSize, s; 158 159 PetscFunctionBeginHot; 160 PetscCall(DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, &star)); 161 for (s = 0; s < starSize * 2; s += 2) { 162 const PetscInt *closure = NULL; 163 PetscInt closureSize, c, q; 164 165 PetscCall(DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure)); 166 for (c = 0; c < closureSize * 2; c += 2) { 167 for (q = 0; q < numAdj || ((void)(adj[numAdj++] = closure[c]), 0); ++q) { 168 if (closure[c] == adj[q]) break; 169 } 170 PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize); 171 } 172 PetscCall(DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure)); 173 } 174 PetscCall(DMPlexRestoreTransitiveClosure(dm, p, useClosure, &starSize, &star)); 175 *adjSize = numAdj; 176 PetscFunctionReturn(0); 177 } 178 179 PetscErrorCode DMPlexGetAdjacency_Internal(DM dm, PetscInt p, PetscBool useCone, PetscBool useTransitiveClosure, PetscBool useAnchors, PetscInt *adjSize, PetscInt *adj[]) 180 { 181 static PetscInt asiz = 0; 182 PetscInt maxAnchors = 1; 183 PetscInt aStart = -1, aEnd = -1; 184 PetscInt maxAdjSize; 185 PetscSection aSec = NULL; 186 IS aIS = NULL; 187 const PetscInt *anchors; 188 DM_Plex *mesh = (DM_Plex *)dm->data; 189 190 PetscFunctionBeginHot; 191 if (useAnchors) { 192 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 193 if (aSec) { 194 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchors)); 195 maxAnchors = PetscMax(1, maxAnchors); 196 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 197 PetscCall(ISGetIndices(aIS, &anchors)); 198 } 199 } 200 if (!*adj) { 201 PetscInt depth, coneSeries, supportSeries, maxC, maxS, pStart, pEnd; 202 203 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 204 PetscCall(DMPlexGetDepth(dm, &depth)); 205 depth = PetscMax(depth, -depth); 206 PetscCall(DMPlexGetMaxSizes(dm, &maxC, &maxS)); 207 coneSeries = (maxC > 1) ? ((PetscPowInt(maxC, depth + 1) - 1) / (maxC - 1)) : depth + 1; 208 supportSeries = (maxS > 1) ? ((PetscPowInt(maxS, depth + 1) - 1) / (maxS - 1)) : depth + 1; 209 asiz = PetscMax(PetscPowInt(maxS, depth) * coneSeries, PetscPowInt(maxC, depth) * supportSeries); 210 asiz *= maxAnchors; 211 asiz = PetscMin(asiz, pEnd - pStart); 212 PetscCall(PetscMalloc1(asiz, adj)); 213 } 214 if (*adjSize < 0) *adjSize = asiz; 215 maxAdjSize = *adjSize; 216 if (mesh->useradjacency) { 217 PetscCall((*mesh->useradjacency)(dm, p, adjSize, *adj, mesh->useradjacencyctx)); 218 } else if (useTransitiveClosure) { 219 PetscCall(DMPlexGetAdjacency_Transitive_Internal(dm, p, useCone, adjSize, *adj)); 220 } else if (useCone) { 221 PetscCall(DMPlexGetAdjacency_Cone_Internal(dm, p, adjSize, *adj)); 222 } else { 223 PetscCall(DMPlexGetAdjacency_Support_Internal(dm, p, adjSize, *adj)); 224 } 225 if (useAnchors && aSec) { 226 PetscInt origSize = *adjSize; 227 PetscInt numAdj = origSize; 228 PetscInt i = 0, j; 229 PetscInt *orig = *adj; 230 231 while (i < origSize) { 232 PetscInt p = orig[i]; 233 PetscInt aDof = 0; 234 235 if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof)); 236 if (aDof) { 237 PetscInt aOff; 238 PetscInt s, q; 239 240 for (j = i + 1; j < numAdj; j++) orig[j - 1] = orig[j]; 241 origSize--; 242 numAdj--; 243 PetscCall(PetscSectionGetOffset(aSec, p, &aOff)); 244 for (s = 0; s < aDof; ++s) { 245 for (q = 0; q < numAdj || ((void)(orig[numAdj++] = anchors[aOff + s]), 0); ++q) { 246 if (anchors[aOff + s] == orig[q]) break; 247 } 248 PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize); 249 } 250 } else { 251 i++; 252 } 253 } 254 *adjSize = numAdj; 255 PetscCall(ISRestoreIndices(aIS, &anchors)); 256 } 257 PetscFunctionReturn(0); 258 } 259 260 /*@ 261 DMPlexGetAdjacency - Return all points adjacent to the given point 262 263 Input Parameters: 264 + dm - The DM object 265 - p - The point 266 267 Input/Output Parameters: 268 + adjSize - The maximum size of adj if it is non-NULL, or PETSC_DETERMINE; 269 on output the number of adjacent points 270 - adj - Either NULL so that the array is allocated, or an existing array with size adjSize; 271 on output contains the adjacent points 272 273 Level: advanced 274 275 Notes: 276 The user must PetscFree the adj array if it was not passed in. 277 278 .seealso: `DMSetAdjacency()`, `DMPlexDistribute()`, `DMCreateMatrix()`, `DMPlexPreallocateOperator()` 279 @*/ 280 PetscErrorCode DMPlexGetAdjacency(DM dm, PetscInt p, PetscInt *adjSize, PetscInt *adj[]) 281 { 282 PetscBool useCone, useClosure, useAnchors; 283 284 PetscFunctionBeginHot; 285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 286 PetscValidIntPointer(adjSize, 3); 287 PetscValidPointer(adj, 4); 288 PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure)); 289 PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors)); 290 PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, adjSize, adj)); 291 PetscFunctionReturn(0); 292 } 293 294 /*@ 295 DMPlexCreateTwoSidedProcessSF - Create an SF which just has process connectivity 296 297 Collective on dm 298 299 Input Parameters: 300 + dm - The DM 301 . sfPoint - The PetscSF which encodes point connectivity 302 . rootRankSection - 303 . rootRanks - 304 . leftRankSection - 305 - leafRanks - 306 307 Output Parameters: 308 + processRanks - A list of process neighbors, or NULL 309 - sfProcess - An SF encoding the two-sided process connectivity, or NULL 310 311 Level: developer 312 313 .seealso: `PetscSFCreate()`, `DMPlexCreateProcessSF()` 314 @*/ 315 PetscErrorCode DMPlexCreateTwoSidedProcessSF(DM dm, PetscSF sfPoint, PetscSection rootRankSection, IS rootRanks, PetscSection leafRankSection, IS leafRanks, IS *processRanks, PetscSF *sfProcess) 316 { 317 const PetscSFNode *remotePoints; 318 PetscInt *localPointsNew; 319 PetscSFNode *remotePointsNew; 320 const PetscInt *nranks; 321 PetscInt *ranksNew; 322 PetscBT neighbors; 323 PetscInt pStart, pEnd, p, numLeaves, l, numNeighbors, n; 324 PetscMPIInt size, proc, rank; 325 326 PetscFunctionBegin; 327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 328 PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2); 329 if (processRanks) PetscValidPointer(processRanks, 7); 330 if (sfProcess) PetscValidPointer(sfProcess, 8); 331 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 332 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 333 PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, NULL, &remotePoints)); 334 PetscCall(PetscBTCreate(size, &neighbors)); 335 PetscCall(PetscBTMemzero(size, neighbors)); 336 /* Compute root-to-leaf process connectivity */ 337 PetscCall(PetscSectionGetChart(rootRankSection, &pStart, &pEnd)); 338 PetscCall(ISGetIndices(rootRanks, &nranks)); 339 for (p = pStart; p < pEnd; ++p) { 340 PetscInt ndof, noff, n; 341 342 PetscCall(PetscSectionGetDof(rootRankSection, p, &ndof)); 343 PetscCall(PetscSectionGetOffset(rootRankSection, p, &noff)); 344 for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n])); 345 } 346 PetscCall(ISRestoreIndices(rootRanks, &nranks)); 347 /* Compute leaf-to-neighbor process connectivity */ 348 PetscCall(PetscSectionGetChart(leafRankSection, &pStart, &pEnd)); 349 PetscCall(ISGetIndices(leafRanks, &nranks)); 350 for (p = pStart; p < pEnd; ++p) { 351 PetscInt ndof, noff, n; 352 353 PetscCall(PetscSectionGetDof(leafRankSection, p, &ndof)); 354 PetscCall(PetscSectionGetOffset(leafRankSection, p, &noff)); 355 for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n])); 356 } 357 PetscCall(ISRestoreIndices(leafRanks, &nranks)); 358 /* Compute leaf-to-root process connectivity */ 359 for (l = 0; l < numLeaves; ++l) PetscBTSet(neighbors, remotePoints[l].rank); 360 /* Calculate edges */ 361 PetscBTClear(neighbors, rank); 362 for (proc = 0, numNeighbors = 0; proc < size; ++proc) { 363 if (PetscBTLookup(neighbors, proc)) ++numNeighbors; 364 } 365 PetscCall(PetscMalloc1(numNeighbors, &ranksNew)); 366 PetscCall(PetscMalloc1(numNeighbors, &localPointsNew)); 367 PetscCall(PetscMalloc1(numNeighbors, &remotePointsNew)); 368 for (proc = 0, n = 0; proc < size; ++proc) { 369 if (PetscBTLookup(neighbors, proc)) { 370 ranksNew[n] = proc; 371 localPointsNew[n] = proc; 372 remotePointsNew[n].index = rank; 373 remotePointsNew[n].rank = proc; 374 ++n; 375 } 376 } 377 PetscCall(PetscBTDestroy(&neighbors)); 378 if (processRanks) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), numNeighbors, ranksNew, PETSC_OWN_POINTER, processRanks)); 379 else PetscCall(PetscFree(ranksNew)); 380 if (sfProcess) { 381 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess)); 382 PetscCall(PetscObjectSetName((PetscObject)*sfProcess, "Two-Sided Process SF")); 383 PetscCall(PetscSFSetFromOptions(*sfProcess)); 384 PetscCall(PetscSFSetGraph(*sfProcess, size, numNeighbors, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER)); 385 } 386 PetscFunctionReturn(0); 387 } 388 389 /*@ 390 DMPlexDistributeOwnership - Compute owner information for shared points. This basically gets two-sided for an SF. 391 392 Collective on dm 393 394 Input Parameter: 395 . dm - The DM 396 397 Output Parameters: 398 + rootSection - The number of leaves for a given root point 399 . rootrank - The rank of each edge into the root point 400 . leafSection - The number of processes sharing a given leaf point 401 - leafrank - The rank of each process sharing a leaf point 402 403 Level: developer 404 405 .seealso: `DMPlexCreateOverlapLabel()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()` 406 @*/ 407 PetscErrorCode DMPlexDistributeOwnership(DM dm, PetscSection rootSection, IS *rootrank, PetscSection leafSection, IS *leafrank) 408 { 409 MPI_Comm comm; 410 PetscSF sfPoint; 411 const PetscInt *rootdegree; 412 PetscInt *myrank, *remoterank; 413 PetscInt pStart, pEnd, p, nedges; 414 PetscMPIInt rank; 415 416 PetscFunctionBegin; 417 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 418 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 419 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 420 PetscCall(DMGetPointSF(dm, &sfPoint)); 421 /* Compute number of leaves for each root */ 422 PetscCall(PetscObjectSetName((PetscObject)rootSection, "Root Section")); 423 PetscCall(PetscSectionSetChart(rootSection, pStart, pEnd)); 424 PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree)); 425 PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree)); 426 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(rootSection, p, rootdegree[p - pStart])); 427 PetscCall(PetscSectionSetUp(rootSection)); 428 /* Gather rank of each leaf to root */ 429 PetscCall(PetscSectionGetStorageSize(rootSection, &nedges)); 430 PetscCall(PetscMalloc1(pEnd - pStart, &myrank)); 431 PetscCall(PetscMalloc1(nedges, &remoterank)); 432 for (p = 0; p < pEnd - pStart; ++p) myrank[p] = rank; 433 PetscCall(PetscSFGatherBegin(sfPoint, MPIU_INT, myrank, remoterank)); 434 PetscCall(PetscSFGatherEnd(sfPoint, MPIU_INT, myrank, remoterank)); 435 PetscCall(PetscFree(myrank)); 436 PetscCall(ISCreateGeneral(comm, nedges, remoterank, PETSC_OWN_POINTER, rootrank)); 437 /* Distribute remote ranks to leaves */ 438 PetscCall(PetscObjectSetName((PetscObject)leafSection, "Leaf Section")); 439 PetscCall(DMPlexDistributeFieldIS(dm, sfPoint, rootSection, *rootrank, leafSection, leafrank)); 440 PetscFunctionReturn(0); 441 } 442 443 #if 0 444 static PetscErrorCode DMPlexCopyOverlapLabels(DM dm, DM ndm) 445 { 446 DM_Plex *mesh = (DM_Plex *) dm->data; 447 DM_Plex *nmesh = (DM_Plex *) ndm->data; 448 449 PetscFunctionBegin; 450 if (mesh->numOvLabels) { 451 const char *name; 452 PetscInt l; 453 454 nmesh->numOvLabels = mesh->numOvLabels; 455 for (l = 0; l < mesh->numOvLabels; ++l) { 456 PetscCall(PetscObjectGetName((PetscObject) mesh->ovLabels[l], &name)); 457 PetscCall(DMGetLabel(ndm, name, &nmesh->ovLabels[l])); 458 nmesh->ovValues[l] = mesh->ovValues[l]; 459 } 460 PetscCall(PetscObjectGetName((PetscObject) mesh->ovExLabel, &name)); 461 PetscCall(DMGetLabel(ndm, name, &nmesh->ovExLabel)); 462 nmesh->ovExValue = mesh->ovExValue; 463 } 464 PetscFunctionReturn(0); 465 } 466 #endif 467 468 /*@C 469 DMPlexCreateOverlapLabel - Compute a label indicating what overlap points should be sent to new processes 470 471 Collective on dm 472 473 Input Parameters: 474 + dm - The DM 475 . levels - Number of overlap levels 476 . rootSection - The number of leaves for a given root point 477 . rootrank - The rank of each edge into the root point 478 . leafSection - The number of processes sharing a given leaf point 479 - leafrank - The rank of each process sharing a leaf point 480 481 Output Parameter: 482 . ovLabel - DMLabel containing remote overlap contributions as point/rank pairings 483 484 Level: developer 485 486 .seealso: `DMPlexCreateOverlapLabelFromLabels()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()` 487 @*/ 488 PetscErrorCode DMPlexCreateOverlapLabel(DM dm, PetscInt levels, PetscSection rootSection, IS rootrank, PetscSection leafSection, IS leafrank, DMLabel *ovLabel) 489 { 490 MPI_Comm comm; 491 DMLabel ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */ 492 PetscSF sfPoint; 493 const PetscSFNode *remote; 494 const PetscInt *local; 495 const PetscInt *nrank, *rrank; 496 PetscInt *adj = NULL; 497 PetscInt pStart, pEnd, p, sStart, sEnd, nleaves, l; 498 PetscMPIInt rank, size; 499 PetscBool flg; 500 501 PetscFunctionBegin; 502 *ovLabel = NULL; 503 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 504 PetscCallMPI(MPI_Comm_size(comm, &size)); 505 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 506 if (size == 1) PetscFunctionReturn(0); 507 PetscCall(DMGetPointSF(dm, &sfPoint)); 508 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 509 if (!levels) { 510 /* Add owned points */ 511 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel)); 512 for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank)); 513 PetscFunctionReturn(0); 514 } 515 PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd)); 516 PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote)); 517 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank)); 518 /* Handle leaves: shared with the root point */ 519 for (l = 0; l < nleaves; ++l) { 520 PetscInt adjSize = PETSC_DETERMINE, a; 521 522 PetscCall(DMPlexGetAdjacency(dm, local ? local[l] : l, &adjSize, &adj)); 523 for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remote[l].rank)); 524 } 525 PetscCall(ISGetIndices(rootrank, &rrank)); 526 PetscCall(ISGetIndices(leafrank, &nrank)); 527 /* Handle roots */ 528 for (p = pStart; p < pEnd; ++p) { 529 PetscInt adjSize = PETSC_DETERMINE, neighbors = 0, noff, n, a; 530 531 if ((p >= sStart) && (p < sEnd)) { 532 /* Some leaves share a root with other leaves on different processes */ 533 PetscCall(PetscSectionGetDof(leafSection, p, &neighbors)); 534 if (neighbors) { 535 PetscCall(PetscSectionGetOffset(leafSection, p, &noff)); 536 PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj)); 537 for (n = 0; n < neighbors; ++n) { 538 const PetscInt remoteRank = nrank[noff + n]; 539 540 if (remoteRank == rank) continue; 541 for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank)); 542 } 543 } 544 } 545 /* Roots are shared with leaves */ 546 PetscCall(PetscSectionGetDof(rootSection, p, &neighbors)); 547 if (!neighbors) continue; 548 PetscCall(PetscSectionGetOffset(rootSection, p, &noff)); 549 PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj)); 550 for (n = 0; n < neighbors; ++n) { 551 const PetscInt remoteRank = rrank[noff + n]; 552 553 if (remoteRank == rank) continue; 554 for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank)); 555 } 556 } 557 PetscCall(PetscFree(adj)); 558 PetscCall(ISRestoreIndices(rootrank, &rrank)); 559 PetscCall(ISRestoreIndices(leafrank, &nrank)); 560 /* Add additional overlap levels */ 561 for (l = 1; l < levels; l++) { 562 /* Propagate point donations over SF to capture remote connections */ 563 PetscCall(DMPlexPartitionLabelPropagate(dm, ovAdjByRank)); 564 /* Add next level of point donations to the label */ 565 PetscCall(DMPlexPartitionLabelAdjacency(dm, ovAdjByRank)); 566 } 567 /* We require the closure in the overlap */ 568 PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank)); 569 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg)); 570 if (flg) { 571 PetscViewer viewer; 572 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer)); 573 PetscCall(DMLabelView(ovAdjByRank, viewer)); 574 } 575 /* Invert sender to receiver label */ 576 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel)); 577 PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel)); 578 /* Add owned points, except for shared local points */ 579 for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank)); 580 for (l = 0; l < nleaves; ++l) { 581 PetscCall(DMLabelClearValue(*ovLabel, local[l], rank)); 582 PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank)); 583 } 584 /* Clean up */ 585 PetscCall(DMLabelDestroy(&ovAdjByRank)); 586 PetscFunctionReturn(0); 587 } 588 589 static PetscErrorCode HandlePoint_Private(DM dm, PetscInt p, PetscSection section, const PetscInt ranks[], PetscInt numExLabels, const DMLabel exLabel[], const PetscInt exValue[], DMLabel ovAdjByRank) 590 { 591 PetscInt neighbors, el; 592 593 PetscFunctionBegin; 594 PetscCall(PetscSectionGetDof(section, p, &neighbors)); 595 if (neighbors) { 596 PetscInt *adj = NULL; 597 PetscInt adjSize = PETSC_DETERMINE, noff, n, a; 598 PetscMPIInt rank; 599 600 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 601 PetscCall(PetscSectionGetOffset(section, p, &noff)); 602 PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj)); 603 for (n = 0; n < neighbors; ++n) { 604 const PetscInt remoteRank = ranks[noff + n]; 605 606 if (remoteRank == rank) continue; 607 for (a = 0; a < adjSize; ++a) { 608 PetscBool insert = PETSC_TRUE; 609 610 for (el = 0; el < numExLabels; ++el) { 611 PetscInt exVal; 612 PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal)); 613 if (exVal == exValue[el]) { 614 insert = PETSC_FALSE; 615 break; 616 } 617 } 618 if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank)); 619 } 620 } 621 PetscCall(PetscFree(adj)); 622 } 623 PetscFunctionReturn(0); 624 } 625 626 /*@C 627 DMPlexCreateOverlapLabelFromLabels - Compute a label indicating what overlap points should be sent to new processes 628 629 Collective on dm 630 631 Input Parameters: 632 + dm - The DM 633 . numLabels - The number of labels to draw candidate points from 634 . label - An array of labels containing candidate points 635 . value - An array of label values marking the candidate points 636 . numExLabels - The number of labels to use for exclusion 637 . exLabel - An array of labels indicating points to be excluded, or NULL 638 . exValue - An array of label values to be excluded, or NULL 639 . rootSection - The number of leaves for a given root point 640 . rootrank - The rank of each edge into the root point 641 . leafSection - The number of processes sharing a given leaf point 642 - leafrank - The rank of each process sharing a leaf point 643 644 Output Parameter: 645 . ovLabel - DMLabel containing remote overlap contributions as point/rank pairings 646 647 Note: 648 The candidate points are only added to the overlap if they are adjacent to a shared point 649 650 Level: developer 651 652 .seealso: `DMPlexCreateOverlapLabel()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()` 653 @*/ 654 PetscErrorCode DMPlexCreateOverlapLabelFromLabels(DM dm, PetscInt numLabels, const DMLabel label[], const PetscInt value[], PetscInt numExLabels, const DMLabel exLabel[], const PetscInt exValue[], PetscSection rootSection, IS rootrank, PetscSection leafSection, IS leafrank, DMLabel *ovLabel) 655 { 656 MPI_Comm comm; 657 DMLabel ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */ 658 PetscSF sfPoint; 659 const PetscSFNode *remote; 660 const PetscInt *local; 661 const PetscInt *nrank, *rrank; 662 PetscInt *adj = NULL; 663 PetscInt pStart, pEnd, p, sStart, sEnd, nleaves, l, el; 664 PetscMPIInt rank, size; 665 PetscBool flg; 666 667 PetscFunctionBegin; 668 *ovLabel = NULL; 669 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 670 PetscCallMPI(MPI_Comm_size(comm, &size)); 671 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 672 if (size == 1) PetscFunctionReturn(0); 673 PetscCall(DMGetPointSF(dm, &sfPoint)); 674 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 675 PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd)); 676 PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote)); 677 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank)); 678 PetscCall(ISGetIndices(rootrank, &rrank)); 679 PetscCall(ISGetIndices(leafrank, &nrank)); 680 for (l = 0; l < numLabels; ++l) { 681 IS valIS; 682 const PetscInt *points; 683 PetscInt n; 684 685 PetscCall(DMLabelGetStratumIS(label[l], value[l], &valIS)); 686 if (!valIS) continue; 687 PetscCall(ISGetIndices(valIS, &points)); 688 PetscCall(ISGetLocalSize(valIS, &n)); 689 for (PetscInt i = 0; i < n; ++i) { 690 const PetscInt p = points[i]; 691 692 if ((p >= sStart) && (p < sEnd)) { 693 PetscInt loc, adjSize = PETSC_DETERMINE; 694 695 /* Handle leaves: shared with the root point */ 696 if (local) PetscCall(PetscFindInt(p, nleaves, local, &loc)); 697 else loc = (p >= 0 && p < nleaves) ? p : -1; 698 if (loc >= 0) { 699 const PetscInt remoteRank = remote[loc].rank; 700 701 PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj)); 702 for (PetscInt a = 0; a < adjSize; ++a) { 703 PetscBool insert = PETSC_TRUE; 704 705 for (el = 0; el < numExLabels; ++el) { 706 PetscInt exVal; 707 PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal)); 708 if (exVal == exValue[el]) { 709 insert = PETSC_FALSE; 710 break; 711 } 712 } 713 if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank)); 714 } 715 } 716 /* Some leaves share a root with other leaves on different processes */ 717 HandlePoint_Private(dm, p, leafSection, nrank, numExLabels, exLabel, exValue, ovAdjByRank); 718 } 719 /* Roots are shared with leaves */ 720 HandlePoint_Private(dm, p, rootSection, rrank, numExLabels, exLabel, exValue, ovAdjByRank); 721 } 722 PetscCall(ISRestoreIndices(valIS, &points)); 723 PetscCall(ISDestroy(&valIS)); 724 } 725 PetscCall(PetscFree(adj)); 726 PetscCall(ISRestoreIndices(rootrank, &rrank)); 727 PetscCall(ISRestoreIndices(leafrank, &nrank)); 728 /* We require the closure in the overlap */ 729 PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank)); 730 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg)); 731 if (flg) { 732 PetscViewer viewer; 733 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer)); 734 PetscCall(DMLabelView(ovAdjByRank, viewer)); 735 } 736 /* Invert sender to receiver label */ 737 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel)); 738 PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel)); 739 /* Add owned points, except for shared local points */ 740 for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank)); 741 for (l = 0; l < nleaves; ++l) { 742 PetscCall(DMLabelClearValue(*ovLabel, local[l], rank)); 743 PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank)); 744 } 745 /* Clean up */ 746 PetscCall(DMLabelDestroy(&ovAdjByRank)); 747 PetscFunctionReturn(0); 748 } 749 750 /*@C 751 DMPlexCreateOverlapMigrationSF - Create an SF describing the new mesh distribution to make the overlap described by the input SF 752 753 Collective on dm 754 755 Input Parameters: 756 + dm - The DM 757 - overlapSF - The SF mapping ghost points in overlap to owner points on other processes 758 759 Output Parameter: 760 . migrationSF - An SF that maps original points in old locations to points in new locations 761 762 Level: developer 763 764 .seealso: `DMPlexCreateOverlapLabel()`, `DMPlexDistributeOverlap()`, `DMPlexDistribute()` 765 @*/ 766 PetscErrorCode DMPlexCreateOverlapMigrationSF(DM dm, PetscSF overlapSF, PetscSF *migrationSF) 767 { 768 MPI_Comm comm; 769 PetscMPIInt rank, size; 770 PetscInt d, dim, p, pStart, pEnd, nroots, nleaves, newLeaves, point, numSharedPoints; 771 PetscInt *pointDepths, *remoteDepths, *ilocal; 772 PetscInt *depthRecv, *depthShift, *depthIdx; 773 PetscSFNode *iremote; 774 PetscSF pointSF; 775 const PetscInt *sharedLocal; 776 const PetscSFNode *overlapRemote, *sharedRemote; 777 778 PetscFunctionBegin; 779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 780 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 781 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 782 PetscCallMPI(MPI_Comm_size(comm, &size)); 783 PetscCall(DMGetDimension(dm, &dim)); 784 785 /* Before building the migration SF we need to know the new stratum offsets */ 786 PetscCall(PetscSFGetGraph(overlapSF, &nroots, &nleaves, NULL, &overlapRemote)); 787 PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths)); 788 for (d = 0; d < dim + 1; d++) { 789 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 790 for (p = pStart; p < pEnd; p++) pointDepths[p] = d; 791 } 792 for (p = 0; p < nleaves; p++) remoteDepths[p] = -1; 793 PetscCall(PetscSFBcastBegin(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE)); 794 PetscCall(PetscSFBcastEnd(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE)); 795 796 /* Count received points in each stratum and compute the internal strata shift */ 797 PetscCall(PetscMalloc3(dim + 1, &depthRecv, dim + 1, &depthShift, dim + 1, &depthIdx)); 798 for (d = 0; d < dim + 1; d++) depthRecv[d] = 0; 799 for (p = 0; p < nleaves; p++) depthRecv[remoteDepths[p]]++; 800 depthShift[dim] = 0; 801 for (d = 0; d < dim; d++) depthShift[d] = depthRecv[dim]; 802 for (d = 1; d < dim; d++) depthShift[d] += depthRecv[0]; 803 for (d = dim - 2; d > 0; d--) depthShift[d] += depthRecv[d + 1]; 804 for (d = 0; d < dim + 1; d++) { 805 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 806 depthIdx[d] = pStart + depthShift[d]; 807 } 808 809 /* Form the overlap SF build an SF that describes the full overlap migration SF */ 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 newLeaves = pEnd - pStart + nleaves; 812 PetscCall(PetscMalloc1(newLeaves, &ilocal)); 813 PetscCall(PetscMalloc1(newLeaves, &iremote)); 814 /* First map local points to themselves */ 815 for (d = 0; d < dim + 1; d++) { 816 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 817 for (p = pStart; p < pEnd; p++) { 818 point = p + depthShift[d]; 819 ilocal[point] = point; 820 iremote[point].index = p; 821 iremote[point].rank = rank; 822 depthIdx[d]++; 823 } 824 } 825 826 /* Add in the remote roots for currently shared points */ 827 PetscCall(DMGetPointSF(dm, &pointSF)); 828 PetscCall(PetscSFGetGraph(pointSF, NULL, &numSharedPoints, &sharedLocal, &sharedRemote)); 829 for (d = 0; d < dim + 1; d++) { 830 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 831 for (p = 0; p < numSharedPoints; p++) { 832 if (pStart <= sharedLocal[p] && sharedLocal[p] < pEnd) { 833 point = sharedLocal[p] + depthShift[d]; 834 iremote[point].index = sharedRemote[p].index; 835 iremote[point].rank = sharedRemote[p].rank; 836 } 837 } 838 } 839 840 /* Now add the incoming overlap points */ 841 for (p = 0; p < nleaves; p++) { 842 point = depthIdx[remoteDepths[p]]; 843 ilocal[point] = point; 844 iremote[point].index = overlapRemote[p].index; 845 iremote[point].rank = overlapRemote[p].rank; 846 depthIdx[remoteDepths[p]]++; 847 } 848 PetscCall(PetscFree2(pointDepths, remoteDepths)); 849 850 PetscCall(PetscSFCreate(comm, migrationSF)); 851 PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Overlap Migration SF")); 852 PetscCall(PetscSFSetFromOptions(*migrationSF)); 853 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 854 PetscCall(PetscSFSetGraph(*migrationSF, pEnd - pStart, newLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 855 856 PetscCall(PetscFree3(depthRecv, depthShift, depthIdx)); 857 PetscFunctionReturn(0); 858 } 859 860 /*@ 861 DMPlexStratifyMigrationSF - Rearrange the leaves of a migration sf for stratification. 862 863 Input Parameters: 864 + dm - The DM 865 - sf - A star forest with non-ordered leaves, usually defining a DM point migration 866 867 Output Parameter: 868 . migrationSF - A star forest with added leaf indirection that ensures the resulting DM is stratified 869 870 Note: 871 This lexicographically sorts by (depth, cellType) 872 873 Level: developer 874 875 .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()` 876 @*/ 877 PetscErrorCode DMPlexStratifyMigrationSF(DM dm, PetscSF sf, PetscSF *migrationSF) 878 { 879 MPI_Comm comm; 880 PetscMPIInt rank, size; 881 PetscInt d, ldepth, depth, dim, p, pStart, pEnd, nroots, nleaves; 882 PetscSFNode *pointDepths, *remoteDepths; 883 PetscInt *ilocal; 884 PetscInt *depthRecv, *depthShift, *depthIdx; 885 PetscInt *ctRecv, *ctShift, *ctIdx; 886 const PetscSFNode *iremote; 887 888 PetscFunctionBegin; 889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 890 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 891 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 892 PetscCallMPI(MPI_Comm_size(comm, &size)); 893 PetscCall(DMPlexGetDepth(dm, &ldepth)); 894 PetscCall(DMGetDimension(dm, &dim)); 895 PetscCall(MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 896 PetscCheck(!(ldepth >= 0) || !(depth != ldepth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, ldepth, depth); 897 PetscCall(PetscLogEventBegin(DMPLEX_PartStratSF, dm, 0, 0, 0)); 898 899 /* Before building the migration SF we need to know the new stratum offsets */ 900 PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, &iremote)); 901 PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths)); 902 for (d = 0; d < depth + 1; ++d) { 903 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 904 for (p = pStart; p < pEnd; ++p) { 905 DMPolytopeType ct; 906 907 PetscCall(DMPlexGetCellType(dm, p, &ct)); 908 pointDepths[p].index = d; 909 pointDepths[p].rank = ct; 910 } 911 } 912 for (p = 0; p < nleaves; ++p) { 913 remoteDepths[p].index = -1; 914 remoteDepths[p].rank = -1; 915 } 916 PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, pointDepths, remoteDepths, MPI_REPLACE)); 917 PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, pointDepths, remoteDepths, MPI_REPLACE)); 918 /* Count received points in each stratum and compute the internal strata shift */ 919 PetscCall(PetscCalloc6(depth + 1, &depthRecv, depth + 1, &depthShift, depth + 1, &depthIdx, DM_NUM_POLYTOPES, &ctRecv, DM_NUM_POLYTOPES, &ctShift, DM_NUM_POLYTOPES, &ctIdx)); 920 for (p = 0; p < nleaves; ++p) { 921 if (remoteDepths[p].rank < 0) { 922 ++depthRecv[remoteDepths[p].index]; 923 } else { 924 ++ctRecv[remoteDepths[p].rank]; 925 } 926 } 927 { 928 PetscInt depths[4], dims[4], shift = 0, i, c; 929 930 /* Cells (depth), Vertices (0), Faces (depth-1), Edges (1) 931 Consider DM_POLYTOPE_FV_GHOST and DM_POLYTOPE_INTERIOR_GHOST as cells 932 */ 933 depths[0] = depth; 934 depths[1] = 0; 935 depths[2] = depth - 1; 936 depths[3] = 1; 937 dims[0] = dim; 938 dims[1] = 0; 939 dims[2] = dim - 1; 940 dims[3] = 1; 941 for (i = 0; i <= depth; ++i) { 942 const PetscInt dep = depths[i]; 943 const PetscInt dim = dims[i]; 944 945 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 946 if (DMPolytopeTypeGetDim((DMPolytopeType)c) != dim && !(i == 0 && (c == DM_POLYTOPE_FV_GHOST || c == DM_POLYTOPE_INTERIOR_GHOST))) continue; 947 ctShift[c] = shift; 948 shift += ctRecv[c]; 949 } 950 depthShift[dep] = shift; 951 shift += depthRecv[dep]; 952 } 953 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 954 const PetscInt ctDim = DMPolytopeTypeGetDim((DMPolytopeType)c); 955 956 if ((ctDim < 0 || ctDim > dim) && (c != DM_POLYTOPE_FV_GHOST && c != DM_POLYTOPE_INTERIOR_GHOST)) { 957 ctShift[c] = shift; 958 shift += ctRecv[c]; 959 } 960 } 961 } 962 /* Derive a new local permutation based on stratified indices */ 963 PetscCall(PetscMalloc1(nleaves, &ilocal)); 964 for (p = 0; p < nleaves; ++p) { 965 const PetscInt dep = remoteDepths[p].index; 966 const DMPolytopeType ct = (DMPolytopeType)remoteDepths[p].rank; 967 968 if ((PetscInt)ct < 0) { 969 ilocal[p] = depthShift[dep] + depthIdx[dep]; 970 ++depthIdx[dep]; 971 } else { 972 ilocal[p] = ctShift[ct] + ctIdx[ct]; 973 ++ctIdx[ct]; 974 } 975 } 976 PetscCall(PetscSFCreate(comm, migrationSF)); 977 PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Migration SF")); 978 PetscCall(PetscSFSetGraph(*migrationSF, nroots, nleaves, ilocal, PETSC_OWN_POINTER, (PetscSFNode *)iremote, PETSC_COPY_VALUES)); 979 PetscCall(PetscFree2(pointDepths, remoteDepths)); 980 PetscCall(PetscFree6(depthRecv, depthShift, depthIdx, ctRecv, ctShift, ctIdx)); 981 PetscCall(PetscLogEventEnd(DMPLEX_PartStratSF, dm, 0, 0, 0)); 982 PetscFunctionReturn(0); 983 } 984 985 /*@ 986 DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution 987 988 Collective on dm 989 990 Input Parameters: 991 + dm - The DMPlex object 992 . pointSF - The PetscSF describing the communication pattern 993 . originalSection - The PetscSection for existing data layout 994 - originalVec - The existing data in a local vector 995 996 Output Parameters: 997 + newSection - The PetscSF describing the new data layout 998 - newVec - The new data in a local vector 999 1000 Level: developer 1001 1002 .seealso: `DMPlexDistribute()`, `DMPlexDistributeFieldIS()`, `DMPlexDistributeData()` 1003 @*/ 1004 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec) 1005 { 1006 PetscSF fieldSF; 1007 PetscInt *remoteOffsets, fieldSize; 1008 PetscScalar *originalValues, *newValues; 1009 1010 PetscFunctionBegin; 1011 PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0)); 1012 PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection)); 1013 1014 PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize)); 1015 PetscCall(VecSetSizes(newVec, fieldSize, PETSC_DETERMINE)); 1016 PetscCall(VecSetType(newVec, dm->vectype)); 1017 1018 PetscCall(VecGetArray(originalVec, &originalValues)); 1019 PetscCall(VecGetArray(newVec, &newValues)); 1020 PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF)); 1021 PetscCall(PetscFree(remoteOffsets)); 1022 PetscCall(PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE)); 1023 PetscCall(PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE)); 1024 PetscCall(PetscSFDestroy(&fieldSF)); 1025 PetscCall(VecRestoreArray(newVec, &newValues)); 1026 PetscCall(VecRestoreArray(originalVec, &originalValues)); 1027 PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0)); 1028 PetscFunctionReturn(0); 1029 } 1030 1031 /*@ 1032 DMPlexDistributeFieldIS - Distribute field data to match a given PetscSF, usually the SF from mesh distribution 1033 1034 Collective on dm 1035 1036 Input Parameters: 1037 + dm - The DMPlex object 1038 . pointSF - The PetscSF describing the communication pattern 1039 . originalSection - The PetscSection for existing data layout 1040 - originalIS - The existing data 1041 1042 Output Parameters: 1043 + newSection - The PetscSF describing the new data layout 1044 - newIS - The new data 1045 1046 Level: developer 1047 1048 .seealso: `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexDistributeData()` 1049 @*/ 1050 PetscErrorCode DMPlexDistributeFieldIS(DM dm, PetscSF pointSF, PetscSection originalSection, IS originalIS, PetscSection newSection, IS *newIS) 1051 { 1052 PetscSF fieldSF; 1053 PetscInt *newValues, *remoteOffsets, fieldSize; 1054 const PetscInt *originalValues; 1055 1056 PetscFunctionBegin; 1057 PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0)); 1058 PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection)); 1059 1060 PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize)); 1061 PetscCall(PetscMalloc1(fieldSize, &newValues)); 1062 1063 PetscCall(ISGetIndices(originalIS, &originalValues)); 1064 PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF)); 1065 PetscCall(PetscFree(remoteOffsets)); 1066 PetscCall(PetscSFBcastBegin(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE)); 1067 PetscCall(PetscSFBcastEnd(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE)); 1068 PetscCall(PetscSFDestroy(&fieldSF)); 1069 PetscCall(ISRestoreIndices(originalIS, &originalValues)); 1070 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pointSF), fieldSize, newValues, PETSC_OWN_POINTER, newIS)); 1071 PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0)); 1072 PetscFunctionReturn(0); 1073 } 1074 1075 /*@ 1076 DMPlexDistributeData - Distribute field data to match a given PetscSF, usually the SF from mesh distribution 1077 1078 Collective on dm 1079 1080 Input Parameters: 1081 + dm - The DMPlex object 1082 . pointSF - The PetscSF describing the communication pattern 1083 . originalSection - The PetscSection for existing data layout 1084 . datatype - The type of data 1085 - originalData - The existing data 1086 1087 Output Parameters: 1088 + newSection - The PetscSection describing the new data layout 1089 - newData - The new data 1090 1091 Level: developer 1092 1093 .seealso: `DMPlexDistribute()`, `DMPlexDistributeField()` 1094 @*/ 1095 PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData) 1096 { 1097 PetscSF fieldSF; 1098 PetscInt *remoteOffsets, fieldSize; 1099 PetscMPIInt dataSize; 1100 1101 PetscFunctionBegin; 1102 PetscCall(PetscLogEventBegin(DMPLEX_DistributeData, dm, 0, 0, 0)); 1103 PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection)); 1104 1105 PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize)); 1106 PetscCallMPI(MPI_Type_size(datatype, &dataSize)); 1107 PetscCall(PetscMalloc(fieldSize * dataSize, newData)); 1108 1109 PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF)); 1110 PetscCall(PetscFree(remoteOffsets)); 1111 PetscCall(PetscSFBcastBegin(fieldSF, datatype, originalData, *newData, MPI_REPLACE)); 1112 PetscCall(PetscSFBcastEnd(fieldSF, datatype, originalData, *newData, MPI_REPLACE)); 1113 PetscCall(PetscSFDestroy(&fieldSF)); 1114 PetscCall(PetscLogEventEnd(DMPLEX_DistributeData, dm, 0, 0, 0)); 1115 PetscFunctionReturn(0); 1116 } 1117 1118 static PetscErrorCode DMPlexDistributeCones(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel) 1119 { 1120 DM_Plex *pmesh = (DM_Plex *)(dmParallel)->data; 1121 MPI_Comm comm; 1122 PetscSF coneSF; 1123 PetscSection originalConeSection, newConeSection; 1124 PetscInt *remoteOffsets, *cones, *globCones, *newCones, newConesSize; 1125 PetscBool flg; 1126 1127 PetscFunctionBegin; 1128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1129 PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5); 1130 PetscCall(PetscLogEventBegin(DMPLEX_DistributeCones, dm, 0, 0, 0)); 1131 /* Distribute cone section */ 1132 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1133 PetscCall(DMPlexGetConeSection(dm, &originalConeSection)); 1134 PetscCall(DMPlexGetConeSection(dmParallel, &newConeSection)); 1135 PetscCall(PetscSFDistributeSection(migrationSF, originalConeSection, &remoteOffsets, newConeSection)); 1136 PetscCall(DMSetUp(dmParallel)); 1137 /* Communicate and renumber cones */ 1138 PetscCall(PetscSFCreateSectionSF(migrationSF, originalConeSection, remoteOffsets, newConeSection, &coneSF)); 1139 PetscCall(PetscFree(remoteOffsets)); 1140 PetscCall(DMPlexGetCones(dm, &cones)); 1141 if (original) { 1142 PetscInt numCones; 1143 1144 PetscCall(PetscSectionGetStorageSize(originalConeSection, &numCones)); 1145 PetscCall(PetscMalloc1(numCones, &globCones)); 1146 PetscCall(ISLocalToGlobalMappingApplyBlock(original, numCones, cones, globCones)); 1147 } else { 1148 globCones = cones; 1149 } 1150 PetscCall(DMPlexGetCones(dmParallel, &newCones)); 1151 PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE)); 1152 PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE)); 1153 if (original) PetscCall(PetscFree(globCones)); 1154 PetscCall(PetscSectionGetStorageSize(newConeSection, &newConesSize)); 1155 PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones)); 1156 if (PetscDefined(USE_DEBUG)) { 1157 PetscInt p; 1158 PetscBool valid = PETSC_TRUE; 1159 for (p = 0; p < newConesSize; ++p) { 1160 if (newCones[p] < 0) { 1161 valid = PETSC_FALSE; 1162 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Point %" PetscInt_FMT " not in overlap SF\n", PetscGlobalRank, p)); 1163 } 1164 } 1165 PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map"); 1166 } 1167 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-cones_view", &flg)); 1168 if (flg) { 1169 PetscCall(PetscPrintf(comm, "Serial Cone Section:\n")); 1170 PetscCall(PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_(comm))); 1171 PetscCall(PetscPrintf(comm, "Parallel Cone Section:\n")); 1172 PetscCall(PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_(comm))); 1173 PetscCall(PetscSFView(coneSF, NULL)); 1174 } 1175 PetscCall(DMPlexGetConeOrientations(dm, &cones)); 1176 PetscCall(DMPlexGetConeOrientations(dmParallel, &newCones)); 1177 PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE)); 1178 PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE)); 1179 PetscCall(PetscSFDestroy(&coneSF)); 1180 PetscCall(PetscLogEventEnd(DMPLEX_DistributeCones, dm, 0, 0, 0)); 1181 /* Create supports and stratify DMPlex */ 1182 { 1183 PetscInt pStart, pEnd; 1184 1185 PetscCall(PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd)); 1186 PetscCall(PetscSectionSetChart(pmesh->supportSection, pStart, pEnd)); 1187 } 1188 PetscCall(DMPlexSymmetrize(dmParallel)); 1189 PetscCall(DMPlexStratify(dmParallel)); 1190 { 1191 PetscBool useCone, useClosure, useAnchors; 1192 1193 PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure)); 1194 PetscCall(DMSetBasicAdjacency(dmParallel, useCone, useClosure)); 1195 PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors)); 1196 PetscCall(DMPlexSetAdjacencyUseAnchors(dmParallel, useAnchors)); 1197 } 1198 PetscFunctionReturn(0); 1199 } 1200 1201 static PetscErrorCode DMPlexDistributeCoordinates(DM dm, PetscSF migrationSF, DM dmParallel) 1202 { 1203 MPI_Comm comm; 1204 DM cdm, cdmParallel; 1205 PetscSection originalCoordSection, newCoordSection; 1206 Vec originalCoordinates, newCoordinates; 1207 PetscInt bs; 1208 const char *name; 1209 const PetscReal *maxCell, *Lstart, *L; 1210 1211 PetscFunctionBegin; 1212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1213 PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3); 1214 1215 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1216 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1217 PetscCall(DMGetCoordinateDM(dmParallel, &cdmParallel)); 1218 PetscCall(DMCopyDisc(cdm, cdmParallel)); 1219 PetscCall(DMGetCoordinateSection(dm, &originalCoordSection)); 1220 PetscCall(DMGetCoordinateSection(dmParallel, &newCoordSection)); 1221 PetscCall(DMGetCoordinatesLocal(dm, &originalCoordinates)); 1222 if (originalCoordinates) { 1223 PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates)); 1224 PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name)); 1225 PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name)); 1226 1227 PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates)); 1228 PetscCall(DMSetCoordinatesLocal(dmParallel, newCoordinates)); 1229 PetscCall(VecGetBlockSize(originalCoordinates, &bs)); 1230 PetscCall(VecSetBlockSize(newCoordinates, bs)); 1231 PetscCall(VecDestroy(&newCoordinates)); 1232 } 1233 1234 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1235 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 1236 PetscCall(DMSetPeriodicity(dmParallel, maxCell, Lstart, L)); 1237 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 1238 if (cdm) { 1239 PetscCall(DMClone(dmParallel, &cdmParallel)); 1240 PetscCall(DMSetCellCoordinateDM(dmParallel, cdmParallel)); 1241 PetscCall(DMCopyDisc(cdm, cdmParallel)); 1242 PetscCall(DMDestroy(&cdmParallel)); 1243 PetscCall(DMGetCellCoordinateSection(dm, &originalCoordSection)); 1244 PetscCall(DMGetCellCoordinatesLocal(dm, &originalCoordinates)); 1245 PetscCall(PetscSectionCreate(comm, &newCoordSection)); 1246 if (originalCoordinates) { 1247 PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates)); 1248 PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name)); 1249 PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name)); 1250 1251 PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates)); 1252 PetscCall(VecGetBlockSize(originalCoordinates, &bs)); 1253 PetscCall(VecSetBlockSize(newCoordinates, bs)); 1254 PetscCall(DMSetCellCoordinateSection(dmParallel, bs, newCoordSection)); 1255 PetscCall(DMSetCellCoordinatesLocal(dmParallel, newCoordinates)); 1256 PetscCall(VecDestroy(&newCoordinates)); 1257 } 1258 PetscCall(PetscSectionDestroy(&newCoordSection)); 1259 } 1260 PetscFunctionReturn(0); 1261 } 1262 1263 static PetscErrorCode DMPlexDistributeLabels(DM dm, PetscSF migrationSF, DM dmParallel) 1264 { 1265 DM_Plex *mesh = (DM_Plex *)dm->data; 1266 MPI_Comm comm; 1267 DMLabel depthLabel; 1268 PetscMPIInt rank; 1269 PetscInt depth, d, numLabels, numLocalLabels, l; 1270 PetscBool hasLabels = PETSC_FALSE, lsendDepth, sendDepth; 1271 PetscObjectState depthState = -1; 1272 1273 PetscFunctionBegin; 1274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1275 PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3); 1276 1277 PetscCall(PetscLogEventBegin(DMPLEX_DistributeLabels, dm, 0, 0, 0)); 1278 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1279 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1280 1281 /* If the user has changed the depth label, communicate it instead */ 1282 PetscCall(DMPlexGetDepth(dm, &depth)); 1283 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 1284 if (depthLabel) PetscCall(PetscObjectStateGet((PetscObject)depthLabel, &depthState)); 1285 lsendDepth = mesh->depthState != depthState ? PETSC_TRUE : PETSC_FALSE; 1286 PetscCall(MPIU_Allreduce(&lsendDepth, &sendDepth, 1, MPIU_BOOL, MPI_LOR, comm)); 1287 if (sendDepth) { 1288 PetscCall(DMPlexGetDepthLabel(dmParallel, &dmParallel->depthLabel)); 1289 PetscCall(DMRemoveLabelBySelf(dmParallel, &dmParallel->depthLabel, PETSC_FALSE)); 1290 } 1291 /* Everyone must have either the same number of labels, or none */ 1292 PetscCall(DMGetNumLabels(dm, &numLocalLabels)); 1293 numLabels = numLocalLabels; 1294 PetscCallMPI(MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm)); 1295 if (numLabels == numLocalLabels) hasLabels = PETSC_TRUE; 1296 for (l = 0; l < numLabels; ++l) { 1297 DMLabel label = NULL, labelNew = NULL; 1298 PetscBool isDepth, lisOutput = PETSC_TRUE, isOutput; 1299 const char *name = NULL; 1300 1301 if (hasLabels) { 1302 PetscCall(DMGetLabelByNum(dm, l, &label)); 1303 /* Skip "depth" because it is recreated */ 1304 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 1305 PetscCall(PetscStrcmp(name, "depth", &isDepth)); 1306 } 1307 PetscCallMPI(MPI_Bcast(&isDepth, 1, MPIU_BOOL, 0, comm)); 1308 if (isDepth && !sendDepth) continue; 1309 PetscCall(DMLabelDistribute(label, migrationSF, &labelNew)); 1310 if (isDepth) { 1311 /* Put in any missing strata which can occur if users are managing the depth label themselves */ 1312 PetscInt gdepth; 1313 1314 PetscCall(MPIU_Allreduce(&depth, &gdepth, 1, MPIU_INT, MPI_MAX, comm)); 1315 PetscCheck(!(depth >= 0) || !(gdepth != depth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, depth, gdepth); 1316 for (d = 0; d <= gdepth; ++d) { 1317 PetscBool has; 1318 1319 PetscCall(DMLabelHasStratum(labelNew, d, &has)); 1320 if (!has) PetscCall(DMLabelAddStratum(labelNew, d)); 1321 } 1322 } 1323 PetscCall(DMAddLabel(dmParallel, labelNew)); 1324 /* Put the output flag in the new label */ 1325 if (hasLabels) PetscCall(DMGetLabelOutput(dm, name, &lisOutput)); 1326 PetscCall(MPIU_Allreduce(&lisOutput, &isOutput, 1, MPIU_BOOL, MPI_LAND, comm)); 1327 PetscCall(PetscObjectGetName((PetscObject)labelNew, &name)); 1328 PetscCall(DMSetLabelOutput(dmParallel, name, isOutput)); 1329 PetscCall(DMLabelDestroy(&labelNew)); 1330 } 1331 { 1332 DMLabel ctLabel; 1333 1334 // Reset label for fast lookup 1335 PetscCall(DMPlexGetCellTypeLabel(dmParallel, &ctLabel)); 1336 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 1337 } 1338 PetscCall(PetscLogEventEnd(DMPLEX_DistributeLabels, dm, 0, 0, 0)); 1339 PetscFunctionReturn(0); 1340 } 1341 1342 static PetscErrorCode DMPlexDistributeSetupTree(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel) 1343 { 1344 DM_Plex *mesh = (DM_Plex *)dm->data; 1345 DM_Plex *pmesh = (DM_Plex *)(dmParallel)->data; 1346 MPI_Comm comm; 1347 DM refTree; 1348 PetscSection origParentSection, newParentSection; 1349 PetscInt *origParents, *origChildIDs; 1350 PetscBool flg; 1351 1352 PetscFunctionBegin; 1353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1354 PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5); 1355 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1356 1357 /* Set up tree */ 1358 PetscCall(DMPlexGetReferenceTree(dm, &refTree)); 1359 PetscCall(DMPlexSetReferenceTree(dmParallel, refTree)); 1360 PetscCall(DMPlexGetTree(dm, &origParentSection, &origParents, &origChildIDs, NULL, NULL)); 1361 if (origParentSection) { 1362 PetscInt pStart, pEnd; 1363 PetscInt *newParents, *newChildIDs, *globParents; 1364 PetscInt *remoteOffsetsParents, newParentSize; 1365 PetscSF parentSF; 1366 1367 PetscCall(DMPlexGetChart(dmParallel, &pStart, &pEnd)); 1368 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmParallel), &newParentSection)); 1369 PetscCall(PetscSectionSetChart(newParentSection, pStart, pEnd)); 1370 PetscCall(PetscSFDistributeSection(migrationSF, origParentSection, &remoteOffsetsParents, newParentSection)); 1371 PetscCall(PetscSFCreateSectionSF(migrationSF, origParentSection, remoteOffsetsParents, newParentSection, &parentSF)); 1372 PetscCall(PetscFree(remoteOffsetsParents)); 1373 PetscCall(PetscSectionGetStorageSize(newParentSection, &newParentSize)); 1374 PetscCall(PetscMalloc2(newParentSize, &newParents, newParentSize, &newChildIDs)); 1375 if (original) { 1376 PetscInt numParents; 1377 1378 PetscCall(PetscSectionGetStorageSize(origParentSection, &numParents)); 1379 PetscCall(PetscMalloc1(numParents, &globParents)); 1380 PetscCall(ISLocalToGlobalMappingApplyBlock(original, numParents, origParents, globParents)); 1381 } else { 1382 globParents = origParents; 1383 } 1384 PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE)); 1385 PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE)); 1386 if (original) PetscCall(PetscFree(globParents)); 1387 PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE)); 1388 PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE)); 1389 PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newParentSize, newParents, NULL, newParents)); 1390 if (PetscDefined(USE_DEBUG)) { 1391 PetscInt p; 1392 PetscBool valid = PETSC_TRUE; 1393 for (p = 0; p < newParentSize; ++p) { 1394 if (newParents[p] < 0) { 1395 valid = PETSC_FALSE; 1396 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Point %" PetscInt_FMT " not in overlap SF\n", p)); 1397 } 1398 } 1399 PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map"); 1400 } 1401 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-parents_view", &flg)); 1402 if (flg) { 1403 PetscCall(PetscPrintf(comm, "Serial Parent Section: \n")); 1404 PetscCall(PetscSectionView(origParentSection, PETSC_VIEWER_STDOUT_(comm))); 1405 PetscCall(PetscPrintf(comm, "Parallel Parent Section: \n")); 1406 PetscCall(PetscSectionView(newParentSection, PETSC_VIEWER_STDOUT_(comm))); 1407 PetscCall(PetscSFView(parentSF, NULL)); 1408 } 1409 PetscCall(DMPlexSetTree(dmParallel, newParentSection, newParents, newChildIDs)); 1410 PetscCall(PetscSectionDestroy(&newParentSection)); 1411 PetscCall(PetscFree2(newParents, newChildIDs)); 1412 PetscCall(PetscSFDestroy(&parentSF)); 1413 } 1414 pmesh->useAnchors = mesh->useAnchors; 1415 PetscFunctionReturn(0); 1416 } 1417 1418 PETSC_UNUSED static PetscErrorCode DMPlexDistributeSF(DM dm, PetscSF migrationSF, DM dmParallel) 1419 { 1420 PetscMPIInt rank, size; 1421 MPI_Comm comm; 1422 1423 PetscFunctionBegin; 1424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1425 PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3); 1426 1427 /* Create point SF for parallel mesh */ 1428 PetscCall(PetscLogEventBegin(DMPLEX_DistributeSF, dm, 0, 0, 0)); 1429 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1430 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1431 PetscCallMPI(MPI_Comm_size(comm, &size)); 1432 { 1433 const PetscInt *leaves; 1434 PetscSFNode *remotePoints, *rowners, *lowners; 1435 PetscInt numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints; 1436 PetscInt pStart, pEnd; 1437 1438 PetscCall(DMPlexGetChart(dmParallel, &pStart, &pEnd)); 1439 PetscCall(PetscSFGetGraph(migrationSF, &numRoots, &numLeaves, &leaves, NULL)); 1440 PetscCall(PetscMalloc2(numRoots, &rowners, numLeaves, &lowners)); 1441 for (p = 0; p < numRoots; p++) { 1442 rowners[p].rank = -1; 1443 rowners[p].index = -1; 1444 } 1445 PetscCall(PetscSFBcastBegin(migrationSF, MPIU_2INT, rowners, lowners, MPI_REPLACE)); 1446 PetscCall(PetscSFBcastEnd(migrationSF, MPIU_2INT, rowners, lowners, MPI_REPLACE)); 1447 for (p = 0; p < numLeaves; ++p) { 1448 if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */ 1449 lowners[p].rank = rank; 1450 lowners[p].index = leaves ? leaves[p] : p; 1451 } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */ 1452 lowners[p].rank = -2; 1453 lowners[p].index = -2; 1454 } 1455 } 1456 for (p = 0; p < numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */ 1457 rowners[p].rank = -3; 1458 rowners[p].index = -3; 1459 } 1460 PetscCall(PetscSFReduceBegin(migrationSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC)); 1461 PetscCall(PetscSFReduceEnd(migrationSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC)); 1462 PetscCall(PetscSFBcastBegin(migrationSF, MPIU_2INT, rowners, lowners, MPI_REPLACE)); 1463 PetscCall(PetscSFBcastEnd(migrationSF, MPIU_2INT, rowners, lowners, MPI_REPLACE)); 1464 for (p = 0; p < numLeaves; ++p) { 1465 PetscCheck(lowners[p].rank >= 0 && lowners[p].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell partition corrupt: point not claimed"); 1466 if (lowners[p].rank != rank) ++numGhostPoints; 1467 } 1468 PetscCall(PetscMalloc1(numGhostPoints, &ghostPoints)); 1469 PetscCall(PetscMalloc1(numGhostPoints, &remotePoints)); 1470 for (p = 0, gp = 0; p < numLeaves; ++p) { 1471 if (lowners[p].rank != rank) { 1472 ghostPoints[gp] = leaves ? leaves[p] : p; 1473 remotePoints[gp].rank = lowners[p].rank; 1474 remotePoints[gp].index = lowners[p].index; 1475 ++gp; 1476 } 1477 } 1478 PetscCall(PetscFree2(rowners, lowners)); 1479 PetscCall(PetscSFSetGraph((dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER)); 1480 PetscCall(PetscSFSetFromOptions((dmParallel)->sf)); 1481 } 1482 { 1483 PetscBool useCone, useClosure, useAnchors; 1484 1485 PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure)); 1486 PetscCall(DMSetBasicAdjacency(dmParallel, useCone, useClosure)); 1487 PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors)); 1488 PetscCall(DMPlexSetAdjacencyUseAnchors(dmParallel, useAnchors)); 1489 } 1490 PetscCall(PetscLogEventEnd(DMPLEX_DistributeSF, dm, 0, 0, 0)); 1491 PetscFunctionReturn(0); 1492 } 1493 1494 /*@ 1495 DMPlexSetPartitionBalance - Should distribution of the DM attempt to balance the shared point partition? 1496 1497 Input Parameters: 1498 + dm - The DMPlex object 1499 - flg - Balance the partition? 1500 1501 Level: intermediate 1502 1503 .seealso: `DMPlexDistribute()`, `DMPlexGetPartitionBalance()` 1504 @*/ 1505 PetscErrorCode DMPlexSetPartitionBalance(DM dm, PetscBool flg) 1506 { 1507 DM_Plex *mesh = (DM_Plex *)dm->data; 1508 1509 PetscFunctionBegin; 1510 mesh->partitionBalance = flg; 1511 PetscFunctionReturn(0); 1512 } 1513 1514 /*@ 1515 DMPlexGetPartitionBalance - Does distribution of the DM attempt to balance the shared point partition? 1516 1517 Input Parameter: 1518 . dm - The DMPlex object 1519 1520 Output Parameter: 1521 . flg - Balance the partition? 1522 1523 Level: intermediate 1524 1525 .seealso: `DMPlexDistribute()`, `DMPlexSetPartitionBalance()` 1526 @*/ 1527 PetscErrorCode DMPlexGetPartitionBalance(DM dm, PetscBool *flg) 1528 { 1529 DM_Plex *mesh = (DM_Plex *)dm->data; 1530 1531 PetscFunctionBegin; 1532 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1533 PetscValidBoolPointer(flg, 2); 1534 *flg = mesh->partitionBalance; 1535 PetscFunctionReturn(0); 1536 } 1537 1538 typedef struct { 1539 PetscInt vote, rank, index; 1540 } Petsc3Int; 1541 1542 /* MaxLoc, but carry a third piece of information around */ 1543 static void MPIAPI MaxLocCarry(void *in_, void *inout_, PetscMPIInt *len_, MPI_Datatype *dtype) 1544 { 1545 Petsc3Int *a = (Petsc3Int *)inout_; 1546 Petsc3Int *b = (Petsc3Int *)in_; 1547 PetscInt i, len = *len_; 1548 for (i = 0; i < len; i++) { 1549 if (a[i].vote < b[i].vote) { 1550 a[i].vote = b[i].vote; 1551 a[i].rank = b[i].rank; 1552 a[i].index = b[i].index; 1553 } else if (a[i].vote <= b[i].vote) { 1554 if (a[i].rank >= b[i].rank) { 1555 a[i].rank = b[i].rank; 1556 a[i].index = b[i].index; 1557 } 1558 } 1559 } 1560 } 1561 1562 /*@C 1563 DMPlexCreatePointSF - Build a point SF from an SF describing a point migration 1564 1565 Input Parameters: 1566 + dm - The source DMPlex object 1567 . migrationSF - The star forest that describes the parallel point remapping 1568 - ownership - Flag causing a vote to determine point ownership 1569 1570 Output Parameter: 1571 . pointSF - The star forest describing the point overlap in the remapped DM 1572 1573 Notes: 1574 Output pointSF is guaranteed to have the array of local indices (leaves) sorted. 1575 1576 Level: developer 1577 1578 .seealso: `DMPlexDistribute()`, `DMPlexDistributeOverlap()` 1579 @*/ 1580 PetscErrorCode DMPlexCreatePointSF(DM dm, PetscSF migrationSF, PetscBool ownership, PetscSF *pointSF) 1581 { 1582 PetscMPIInt rank, size; 1583 PetscInt p, nroots, nleaves, idx, npointLeaves; 1584 PetscInt *pointLocal; 1585 const PetscInt *leaves; 1586 const PetscSFNode *roots; 1587 PetscSFNode *rootNodes, *leafNodes, *pointRemote; 1588 Vec shifts; 1589 const PetscInt numShifts = 13759; 1590 const PetscScalar *shift = NULL; 1591 const PetscBool shiftDebug = PETSC_FALSE; 1592 PetscBool balance; 1593 1594 PetscFunctionBegin; 1595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1596 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1597 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1598 PetscCall(PetscLogEventBegin(DMPLEX_CreatePointSF, dm, 0, 0, 0)); 1599 1600 PetscCall(DMPlexGetPartitionBalance(dm, &balance)); 1601 PetscCall(PetscSFGetGraph(migrationSF, &nroots, &nleaves, &leaves, &roots)); 1602 PetscCall(PetscMalloc2(nroots, &rootNodes, nleaves, &leafNodes)); 1603 if (ownership) { 1604 MPI_Op op; 1605 MPI_Datatype datatype; 1606 Petsc3Int *rootVote = NULL, *leafVote = NULL; 1607 /* If balancing, we compute a random cyclic shift of the rank for each remote point. That way, the max will evenly distribute among ranks. */ 1608 if (balance) { 1609 PetscRandom r; 1610 1611 PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &r)); 1612 PetscCall(PetscRandomSetInterval(r, 0, 2467 * size)); 1613 PetscCall(VecCreate(PETSC_COMM_SELF, &shifts)); 1614 PetscCall(VecSetSizes(shifts, numShifts, numShifts)); 1615 PetscCall(VecSetType(shifts, VECSTANDARD)); 1616 PetscCall(VecSetRandom(shifts, r)); 1617 PetscCall(PetscRandomDestroy(&r)); 1618 PetscCall(VecGetArrayRead(shifts, &shift)); 1619 } 1620 1621 PetscCall(PetscMalloc1(nroots, &rootVote)); 1622 PetscCall(PetscMalloc1(nleaves, &leafVote)); 1623 /* Point ownership vote: Process with highest rank owns shared points */ 1624 for (p = 0; p < nleaves; ++p) { 1625 if (shiftDebug) { 1626 PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Point %" PetscInt_FMT " RemotePoint %" PetscInt_FMT " Shift %" PetscInt_FMT " MyRank %" PetscInt_FMT "\n", rank, leaves ? leaves[p] : p, roots[p].index, 1627 (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]), (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size)); 1628 } 1629 /* Either put in a bid or we know we own it */ 1630 leafVote[p].vote = (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size; 1631 leafVote[p].rank = rank; 1632 leafVote[p].index = p; 1633 } 1634 for (p = 0; p < nroots; p++) { 1635 /* Root must not participate in the reduction, flag so that MAXLOC does not use */ 1636 rootVote[p].vote = -3; 1637 rootVote[p].rank = -3; 1638 rootVote[p].index = -3; 1639 } 1640 PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &datatype)); 1641 PetscCallMPI(MPI_Type_commit(&datatype)); 1642 PetscCallMPI(MPI_Op_create(&MaxLocCarry, 1, &op)); 1643 PetscCall(PetscSFReduceBegin(migrationSF, datatype, leafVote, rootVote, op)); 1644 PetscCall(PetscSFReduceEnd(migrationSF, datatype, leafVote, rootVote, op)); 1645 PetscCallMPI(MPI_Op_free(&op)); 1646 PetscCallMPI(MPI_Type_free(&datatype)); 1647 for (p = 0; p < nroots; p++) { 1648 rootNodes[p].rank = rootVote[p].rank; 1649 rootNodes[p].index = rootVote[p].index; 1650 } 1651 PetscCall(PetscFree(leafVote)); 1652 PetscCall(PetscFree(rootVote)); 1653 } else { 1654 for (p = 0; p < nroots; p++) { 1655 rootNodes[p].index = -1; 1656 rootNodes[p].rank = rank; 1657 } 1658 for (p = 0; p < nleaves; p++) { 1659 /* Write new local id into old location */ 1660 if (roots[p].rank == rank) rootNodes[roots[p].index].index = leaves ? leaves[p] : p; 1661 } 1662 } 1663 PetscCall(PetscSFBcastBegin(migrationSF, MPIU_2INT, rootNodes, leafNodes, MPI_REPLACE)); 1664 PetscCall(PetscSFBcastEnd(migrationSF, MPIU_2INT, rootNodes, leafNodes, MPI_REPLACE)); 1665 1666 for (npointLeaves = 0, p = 0; p < nleaves; p++) { 1667 if (leafNodes[p].rank != rank) npointLeaves++; 1668 } 1669 PetscCall(PetscMalloc1(npointLeaves, &pointLocal)); 1670 PetscCall(PetscMalloc1(npointLeaves, &pointRemote)); 1671 for (idx = 0, p = 0; p < nleaves; p++) { 1672 if (leafNodes[p].rank != rank) { 1673 /* Note that pointLocal is automatically sorted as it is sublist of 0, ..., nleaves-1 */ 1674 pointLocal[idx] = p; 1675 pointRemote[idx] = leafNodes[p]; 1676 idx++; 1677 } 1678 } 1679 if (shift) { 1680 PetscCall(VecRestoreArrayRead(shifts, &shift)); 1681 PetscCall(VecDestroy(&shifts)); 1682 } 1683 if (shiftDebug) PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)dm), PETSC_STDOUT)); 1684 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), pointSF)); 1685 PetscCall(PetscSFSetFromOptions(*pointSF)); 1686 PetscCall(PetscSFSetGraph(*pointSF, nleaves, npointLeaves, pointLocal, PETSC_OWN_POINTER, pointRemote, PETSC_OWN_POINTER)); 1687 PetscCall(PetscFree2(rootNodes, leafNodes)); 1688 PetscCall(PetscLogEventEnd(DMPLEX_CreatePointSF, dm, 0, 0, 0)); 1689 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, *pointSF, PETSC_FALSE)); 1690 PetscFunctionReturn(0); 1691 } 1692 1693 /*@C 1694 DMPlexMigrate - Migrates internal DM data over the supplied star forest 1695 1696 Collective on dm 1697 1698 Input Parameters: 1699 + dm - The source DMPlex object 1700 - sf - The star forest communication context describing the migration pattern 1701 1702 Output Parameter: 1703 . targetDM - The target DMPlex object 1704 1705 Level: intermediate 1706 1707 .seealso: `DMPlexDistribute()`, `DMPlexDistributeOverlap()` 1708 @*/ 1709 PetscErrorCode DMPlexMigrate(DM dm, PetscSF sf, DM targetDM) 1710 { 1711 MPI_Comm comm; 1712 PetscInt dim, cdim, nroots; 1713 PetscSF sfPoint; 1714 ISLocalToGlobalMapping ltogMigration; 1715 ISLocalToGlobalMapping ltogOriginal = NULL; 1716 1717 PetscFunctionBegin; 1718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1719 PetscCall(PetscLogEventBegin(DMPLEX_Migrate, dm, 0, 0, 0)); 1720 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1721 PetscCall(DMGetDimension(dm, &dim)); 1722 PetscCall(DMSetDimension(targetDM, dim)); 1723 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1724 PetscCall(DMSetCoordinateDim(targetDM, cdim)); 1725 1726 /* Check for a one-to-all distribution pattern */ 1727 PetscCall(DMGetPointSF(dm, &sfPoint)); 1728 PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL)); 1729 if (nroots >= 0) { 1730 IS isOriginal; 1731 PetscInt n, size, nleaves; 1732 PetscInt *numbering_orig, *numbering_new; 1733 1734 /* Get the original point numbering */ 1735 PetscCall(DMPlexCreatePointNumbering(dm, &isOriginal)); 1736 PetscCall(ISLocalToGlobalMappingCreateIS(isOriginal, <ogOriginal)); 1737 PetscCall(ISLocalToGlobalMappingGetSize(ltogOriginal, &size)); 1738 PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltogOriginal, (const PetscInt **)&numbering_orig)); 1739 /* Convert to positive global numbers */ 1740 for (n = 0; n < size; n++) { 1741 if (numbering_orig[n] < 0) numbering_orig[n] = -(numbering_orig[n] + 1); 1742 } 1743 /* Derive the new local-to-global mapping from the old one */ 1744 PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, NULL, NULL)); 1745 PetscCall(PetscMalloc1(nleaves, &numbering_new)); 1746 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE)); 1747 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE)); 1748 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, nleaves, numbering_new, PETSC_OWN_POINTER, <ogMigration)); 1749 PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogOriginal, (const PetscInt **)&numbering_orig)); 1750 PetscCall(ISDestroy(&isOriginal)); 1751 } else { 1752 /* One-to-all distribution pattern: We can derive LToG from SF */ 1753 PetscCall(ISLocalToGlobalMappingCreateSF(sf, 0, <ogMigration)); 1754 } 1755 PetscCall(PetscObjectSetName((PetscObject)ltogMigration, "Point renumbering for DM migration")); 1756 PetscCall(ISLocalToGlobalMappingViewFromOptions(ltogMigration, (PetscObject)dm, "-partition_view")); 1757 /* Migrate DM data to target DM */ 1758 PetscCall(DMPlexDistributeCones(dm, sf, ltogOriginal, ltogMigration, targetDM)); 1759 PetscCall(DMPlexDistributeLabels(dm, sf, targetDM)); 1760 PetscCall(DMPlexDistributeCoordinates(dm, sf, targetDM)); 1761 PetscCall(DMPlexDistributeSetupTree(dm, sf, ltogOriginal, ltogMigration, targetDM)); 1762 PetscCall(ISLocalToGlobalMappingDestroy(<ogOriginal)); 1763 PetscCall(ISLocalToGlobalMappingDestroy(<ogMigration)); 1764 PetscCall(PetscLogEventEnd(DMPLEX_Migrate, dm, 0, 0, 0)); 1765 PetscFunctionReturn(0); 1766 } 1767 1768 /*@C 1769 DMPlexDistribute - Distributes the mesh and any associated sections. 1770 1771 Collective on dm 1772 1773 Input Parameters: 1774 + dm - The original DMPlex object 1775 - overlap - The overlap of partitions, 0 is the default 1776 1777 Output Parameters: 1778 + sf - The PetscSF used for point distribution, or NULL if not needed 1779 - dmParallel - The distributed DMPlex object 1780 1781 Note: If the mesh was not distributed, the output dmParallel will be NULL. 1782 1783 The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function 1784 representation on the mesh. 1785 1786 Level: intermediate 1787 1788 .seealso: `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexGetOverlap()` 1789 @*/ 1790 PetscErrorCode DMPlexDistribute(DM dm, PetscInt overlap, PetscSF *sf, DM *dmParallel) 1791 { 1792 MPI_Comm comm; 1793 PetscPartitioner partitioner; 1794 IS cellPart; 1795 PetscSection cellPartSection; 1796 DM dmCoord; 1797 DMLabel lblPartition, lblMigration; 1798 PetscSF sfMigration, sfStratified, sfPoint; 1799 PetscBool flg, balance; 1800 PetscMPIInt rank, size; 1801 1802 PetscFunctionBegin; 1803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1804 PetscValidLogicalCollectiveInt(dm, overlap, 2); 1805 if (sf) PetscValidPointer(sf, 3); 1806 PetscValidPointer(dmParallel, 4); 1807 1808 if (sf) *sf = NULL; 1809 *dmParallel = NULL; 1810 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1811 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1812 PetscCallMPI(MPI_Comm_size(comm, &size)); 1813 if (size == 1) PetscFunctionReturn(0); 1814 1815 PetscCall(PetscLogEventBegin(DMPLEX_Distribute, dm, 0, 0, 0)); 1816 /* Create cell partition */ 1817 PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0)); 1818 PetscCall(PetscSectionCreate(comm, &cellPartSection)); 1819 PetscCall(DMPlexGetPartitioner(dm, &partitioner)); 1820 PetscCall(PetscPartitionerDMPlexPartition(partitioner, dm, NULL, cellPartSection, &cellPart)); 1821 PetscCall(PetscLogEventBegin(DMPLEX_PartSelf, dm, 0, 0, 0)); 1822 { 1823 /* Convert partition to DMLabel */ 1824 IS is; 1825 PetscHSetI ht; 1826 const PetscInt *points; 1827 PetscInt *iranks; 1828 PetscInt pStart, pEnd, proc, npoints, poff = 0, nranks; 1829 1830 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point Partition", &lblPartition)); 1831 /* Preallocate strata */ 1832 PetscCall(PetscHSetICreate(&ht)); 1833 PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd)); 1834 for (proc = pStart; proc < pEnd; proc++) { 1835 PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints)); 1836 if (npoints) PetscCall(PetscHSetIAdd(ht, proc)); 1837 } 1838 PetscCall(PetscHSetIGetSize(ht, &nranks)); 1839 PetscCall(PetscMalloc1(nranks, &iranks)); 1840 PetscCall(PetscHSetIGetElems(ht, &poff, iranks)); 1841 PetscCall(PetscHSetIDestroy(&ht)); 1842 PetscCall(DMLabelAddStrata(lblPartition, nranks, iranks)); 1843 PetscCall(PetscFree(iranks)); 1844 /* Inline DMPlexPartitionLabelClosure() */ 1845 PetscCall(ISGetIndices(cellPart, &points)); 1846 PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd)); 1847 for (proc = pStart; proc < pEnd; proc++) { 1848 PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints)); 1849 if (!npoints) continue; 1850 PetscCall(PetscSectionGetOffset(cellPartSection, proc, &poff)); 1851 PetscCall(DMPlexClosurePoints_Private(dm, npoints, points + poff, &is)); 1852 PetscCall(DMLabelSetStratumIS(lblPartition, proc, is)); 1853 PetscCall(ISDestroy(&is)); 1854 } 1855 PetscCall(ISRestoreIndices(cellPart, &points)); 1856 } 1857 PetscCall(PetscLogEventEnd(DMPLEX_PartSelf, dm, 0, 0, 0)); 1858 1859 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point migration", &lblMigration)); 1860 PetscCall(DMPlexPartitionLabelInvert(dm, lblPartition, NULL, lblMigration)); 1861 PetscCall(DMPlexPartitionLabelCreateSF(dm, lblMigration, &sfMigration)); 1862 PetscCall(DMPlexStratifyMigrationSF(dm, sfMigration, &sfStratified)); 1863 PetscCall(PetscSFDestroy(&sfMigration)); 1864 sfMigration = sfStratified; 1865 PetscCall(PetscSFSetUp(sfMigration)); 1866 PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0)); 1867 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-partition_view", &flg)); 1868 if (flg) { 1869 PetscCall(DMLabelView(lblPartition, PETSC_VIEWER_STDOUT_(comm))); 1870 PetscCall(PetscSFView(sfMigration, PETSC_VIEWER_STDOUT_(comm))); 1871 } 1872 1873 /* Create non-overlapping parallel DM and migrate internal data */ 1874 PetscCall(DMPlexCreate(comm, dmParallel)); 1875 PetscCall(PetscObjectSetName((PetscObject)*dmParallel, "Parallel Mesh")); 1876 PetscCall(DMPlexMigrate(dm, sfMigration, *dmParallel)); 1877 1878 /* Build the point SF without overlap */ 1879 PetscCall(DMPlexGetPartitionBalance(dm, &balance)); 1880 PetscCall(DMPlexSetPartitionBalance(*dmParallel, balance)); 1881 PetscCall(DMPlexCreatePointSF(*dmParallel, sfMigration, PETSC_TRUE, &sfPoint)); 1882 PetscCall(DMSetPointSF(*dmParallel, sfPoint)); 1883 PetscCall(DMGetCoordinateDM(*dmParallel, &dmCoord)); 1884 if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint)); 1885 if (flg) PetscCall(PetscSFView(sfPoint, NULL)); 1886 1887 if (overlap > 0) { 1888 DM dmOverlap; 1889 PetscInt nroots, nleaves, noldleaves, l; 1890 const PetscInt *oldLeaves; 1891 PetscSFNode *newRemote, *permRemote; 1892 const PetscSFNode *oldRemote; 1893 PetscSF sfOverlap, sfOverlapPoint; 1894 1895 /* Add the partition overlap to the distributed DM */ 1896 PetscCall(DMPlexDistributeOverlap(*dmParallel, overlap, &sfOverlap, &dmOverlap)); 1897 PetscCall(DMDestroy(dmParallel)); 1898 *dmParallel = dmOverlap; 1899 if (flg) { 1900 PetscCall(PetscPrintf(comm, "Overlap Migration SF:\n")); 1901 PetscCall(PetscSFView(sfOverlap, NULL)); 1902 } 1903 1904 /* Re-map the migration SF to establish the full migration pattern */ 1905 PetscCall(PetscSFGetGraph(sfMigration, &nroots, &noldleaves, &oldLeaves, &oldRemote)); 1906 PetscCall(PetscSFGetGraph(sfOverlap, NULL, &nleaves, NULL, NULL)); 1907 PetscCall(PetscMalloc1(nleaves, &newRemote)); 1908 /* oldRemote: original root point mapping to original leaf point 1909 newRemote: original leaf point mapping to overlapped leaf point */ 1910 if (oldLeaves) { 1911 /* After stratification, the migration remotes may not be in root (canonical) order, so we reorder using the leaf numbering */ 1912 PetscCall(PetscMalloc1(noldleaves, &permRemote)); 1913 for (l = 0; l < noldleaves; ++l) permRemote[oldLeaves[l]] = oldRemote[l]; 1914 oldRemote = permRemote; 1915 } 1916 PetscCall(PetscSFBcastBegin(sfOverlap, MPIU_2INT, oldRemote, newRemote, MPI_REPLACE)); 1917 PetscCall(PetscSFBcastEnd(sfOverlap, MPIU_2INT, oldRemote, newRemote, MPI_REPLACE)); 1918 if (oldLeaves) PetscCall(PetscFree(oldRemote)); 1919 PetscCall(PetscSFCreate(comm, &sfOverlapPoint)); 1920 PetscCall(PetscSFSetGraph(sfOverlapPoint, nroots, nleaves, NULL, PETSC_OWN_POINTER, newRemote, PETSC_OWN_POINTER)); 1921 PetscCall(PetscSFDestroy(&sfOverlap)); 1922 PetscCall(PetscSFDestroy(&sfMigration)); 1923 sfMigration = sfOverlapPoint; 1924 } 1925 /* Cleanup Partition */ 1926 PetscCall(DMLabelDestroy(&lblPartition)); 1927 PetscCall(DMLabelDestroy(&lblMigration)); 1928 PetscCall(PetscSectionDestroy(&cellPartSection)); 1929 PetscCall(ISDestroy(&cellPart)); 1930 /* Copy discretization */ 1931 PetscCall(DMCopyDisc(dm, *dmParallel)); 1932 /* Create sfNatural */ 1933 if (dm->useNatural) { 1934 PetscSection section; 1935 1936 PetscCall(DMSetUseNatural(*dmParallel, PETSC_TRUE)); 1937 PetscCall(DMGetLocalSection(dm, §ion)); 1938 1939 /* First DM with useNatural = PETSC_TRUE is considered natural */ 1940 /* sfMigration and sfNatural are respectively the point and dofs SFs mapping to this natural DM */ 1941 /* Compose with a previous sfNatural if present */ 1942 if (dm->sfNatural) { 1943 PetscSF natSF; 1944 1945 PetscCall(DMPlexCreateGlobalToNaturalSF(*dmParallel, section, sfMigration, &natSF)); 1946 PetscCall(PetscSFCompose(dm->sfNatural, natSF, &(*dmParallel)->sfNatural)); 1947 PetscCall(PetscSFDestroy(&natSF)); 1948 } else { 1949 PetscCall(DMPlexCreateGlobalToNaturalSF(*dmParallel, section, sfMigration, &(*dmParallel)->sfNatural)); 1950 } 1951 /* Compose with a previous sfMigration if present */ 1952 if (dm->sfMigration) { 1953 PetscSF naturalPointSF; 1954 1955 PetscCall(PetscSFCompose(dm->sfMigration, sfMigration, &naturalPointSF)); 1956 PetscCall(PetscSFDestroy(&sfMigration)); 1957 sfMigration = naturalPointSF; 1958 } 1959 } 1960 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *dmParallel)); 1961 /* Cleanup */ 1962 if (sf) { 1963 *sf = sfMigration; 1964 } else PetscCall(PetscSFDestroy(&sfMigration)); 1965 PetscCall(PetscSFDestroy(&sfPoint)); 1966 PetscCall(PetscLogEventEnd(DMPLEX_Distribute, dm, 0, 0, 0)); 1967 PetscFunctionReturn(0); 1968 } 1969 1970 /*@C 1971 DMPlexDistributeOverlap - Add partition overlap to a distributed non-overlapping DM. 1972 1973 Collective on dm 1974 1975 Input Parameters: 1976 + dm - The non-overlapping distributed DMPlex object 1977 - overlap - The overlap of partitions (the same on all ranks) 1978 1979 Output Parameters: 1980 + sf - The PetscSF used for point distribution 1981 - dmOverlap - The overlapping distributed DMPlex object, or NULL 1982 1983 Notes: 1984 If the mesh was not distributed, the return value is NULL. 1985 1986 The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function 1987 representation on the mesh. 1988 1989 Options Database Keys: 1990 + -dm_plex_overlap_labels <name1,name2,...> - List of overlap label names 1991 . -dm_plex_overlap_values <int1,int2,...> - List of overlap label values 1992 . -dm_plex_overlap_exclude_label <name> - Label used to exclude points from overlap 1993 - -dm_plex_overlap_exclude_value <int> - Label value used to exclude points from overlap 1994 1995 Level: advanced 1996 1997 .seealso: `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexCreateOverlapLabel()`, `DMPlexGetOverlap()` 1998 @*/ 1999 PetscErrorCode DMPlexDistributeOverlap(DM dm, PetscInt overlap, PetscSF *sf, DM *dmOverlap) 2000 { 2001 DM_Plex *mesh = (DM_Plex *)dm->data; 2002 MPI_Comm comm; 2003 PetscMPIInt size, rank; 2004 PetscSection rootSection, leafSection; 2005 IS rootrank, leafrank; 2006 DM dmCoord; 2007 DMLabel lblOverlap; 2008 PetscSF sfOverlap, sfStratified, sfPoint; 2009 2010 PetscFunctionBegin; 2011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2012 PetscValidLogicalCollectiveInt(dm, overlap, 2); 2013 if (sf) PetscValidPointer(sf, 3); 2014 PetscValidPointer(dmOverlap, 4); 2015 2016 if (sf) *sf = NULL; 2017 *dmOverlap = NULL; 2018 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2019 PetscCallMPI(MPI_Comm_size(comm, &size)); 2020 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2021 if (size == 1) PetscFunctionReturn(0); 2022 { 2023 // We need to get options for the _already_distributed mesh, so it must be done here 2024 PetscInt overlap; 2025 const char *prefix; 2026 char oldPrefix[PETSC_MAX_PATH_LEN]; 2027 2028 oldPrefix[0] = '\0'; 2029 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 2030 PetscCall(PetscStrcpy(oldPrefix, prefix)); 2031 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "dist_")); 2032 PetscCall(DMPlexGetOverlap(dm, &overlap)); 2033 PetscObjectOptionsBegin((PetscObject)dm); 2034 PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap)); 2035 PetscOptionsEnd(); 2036 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix[0] == '\0' ? NULL : oldPrefix)); 2037 } 2038 PetscCall(PetscLogEventBegin(DMPLEX_DistributeOverlap, dm, 0, 0, 0)); 2039 /* Compute point overlap with neighbouring processes on the distributed DM */ 2040 PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0)); 2041 PetscCall(PetscSectionCreate(comm, &rootSection)); 2042 PetscCall(PetscSectionCreate(comm, &leafSection)); 2043 PetscCall(DMPlexDistributeOwnership(dm, rootSection, &rootrank, leafSection, &leafrank)); 2044 if (mesh->numOvLabels) PetscCall(DMPlexCreateOverlapLabelFromLabels(dm, mesh->numOvLabels, mesh->ovLabels, mesh->ovValues, mesh->numOvExLabels, mesh->ovExLabels, mesh->ovExValues, rootSection, rootrank, leafSection, leafrank, &lblOverlap)); 2045 else PetscCall(DMPlexCreateOverlapLabel(dm, overlap, rootSection, rootrank, leafSection, leafrank, &lblOverlap)); 2046 /* Convert overlap label to stratified migration SF */ 2047 PetscCall(DMPlexPartitionLabelCreateSF(dm, lblOverlap, &sfOverlap)); 2048 PetscCall(DMPlexStratifyMigrationSF(dm, sfOverlap, &sfStratified)); 2049 PetscCall(PetscSFDestroy(&sfOverlap)); 2050 sfOverlap = sfStratified; 2051 PetscCall(PetscObjectSetName((PetscObject)sfOverlap, "Overlap SF")); 2052 PetscCall(PetscSFSetFromOptions(sfOverlap)); 2053 2054 PetscCall(PetscSectionDestroy(&rootSection)); 2055 PetscCall(PetscSectionDestroy(&leafSection)); 2056 PetscCall(ISDestroy(&rootrank)); 2057 PetscCall(ISDestroy(&leafrank)); 2058 PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0)); 2059 2060 /* Build the overlapping DM */ 2061 PetscCall(DMPlexCreate(comm, dmOverlap)); 2062 PetscCall(PetscObjectSetName((PetscObject)*dmOverlap, "Parallel Mesh")); 2063 PetscCall(DMPlexMigrate(dm, sfOverlap, *dmOverlap)); 2064 /* Store the overlap in the new DM */ 2065 PetscCall(DMPlexSetOverlap_Plex(*dmOverlap, dm, overlap)); 2066 /* Build the new point SF */ 2067 PetscCall(DMPlexCreatePointSF(*dmOverlap, sfOverlap, PETSC_FALSE, &sfPoint)); 2068 PetscCall(DMSetPointSF(*dmOverlap, sfPoint)); 2069 PetscCall(DMGetCoordinateDM(*dmOverlap, &dmCoord)); 2070 if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint)); 2071 PetscCall(DMGetCellCoordinateDM(*dmOverlap, &dmCoord)); 2072 if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint)); 2073 PetscCall(PetscSFDestroy(&sfPoint)); 2074 /* Cleanup overlap partition */ 2075 PetscCall(DMLabelDestroy(&lblOverlap)); 2076 if (sf) *sf = sfOverlap; 2077 else PetscCall(PetscSFDestroy(&sfOverlap)); 2078 PetscCall(PetscLogEventEnd(DMPLEX_DistributeOverlap, dm, 0, 0, 0)); 2079 PetscFunctionReturn(0); 2080 } 2081 2082 PetscErrorCode DMPlexGetOverlap_Plex(DM dm, PetscInt *overlap) 2083 { 2084 DM_Plex *mesh = (DM_Plex *)dm->data; 2085 2086 PetscFunctionBegin; 2087 *overlap = mesh->overlap; 2088 PetscFunctionReturn(0); 2089 } 2090 2091 PetscErrorCode DMPlexSetOverlap_Plex(DM dm, DM dmSrc, PetscInt overlap) 2092 { 2093 DM_Plex *mesh = NULL; 2094 DM_Plex *meshSrc = NULL; 2095 2096 PetscFunctionBegin; 2097 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX); 2098 mesh = (DM_Plex *)dm->data; 2099 mesh->overlap = overlap; 2100 if (dmSrc) { 2101 PetscValidHeaderSpecificType(dmSrc, DM_CLASSID, 2, DMPLEX); 2102 meshSrc = (DM_Plex *)dmSrc->data; 2103 mesh->overlap += meshSrc->overlap; 2104 } 2105 PetscFunctionReturn(0); 2106 } 2107 2108 /*@ 2109 DMPlexGetOverlap - Get the width of the cell overlap 2110 2111 Not collective 2112 2113 Input Parameter: 2114 . dm - The DM 2115 2116 Output Parameter: 2117 . overlap - the width of the cell overlap 2118 2119 Level: intermediate 2120 2121 .seealso: `DMPlexSetOverlap()`, `DMPlexDistribute()` 2122 @*/ 2123 PetscErrorCode DMPlexGetOverlap(DM dm, PetscInt *overlap) 2124 { 2125 PetscFunctionBegin; 2126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2127 PetscValidIntPointer(overlap, 2); 2128 PetscUseMethod(dm, "DMPlexGetOverlap_C", (DM, PetscInt *), (dm, overlap)); 2129 PetscFunctionReturn(0); 2130 } 2131 2132 /*@ 2133 DMPlexSetOverlap - Set the width of the cell overlap 2134 2135 Logically collective 2136 2137 Input Parameters: 2138 + dm - The DM 2139 . dmSrc - The DM that produced this one, or NULL 2140 - overlap - the width of the cell overlap 2141 2142 Note: 2143 The overlap from dmSrc is added to dm 2144 2145 Level: intermediate 2146 2147 .seealso: `DMPlexGetOverlap()`, `DMPlexDistribute()` 2148 @*/ 2149 PetscErrorCode DMPlexSetOverlap(DM dm, DM dmSrc, PetscInt overlap) 2150 { 2151 PetscFunctionBegin; 2152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2153 PetscValidLogicalCollectiveInt(dm, overlap, 3); 2154 PetscTryMethod(dm, "DMPlexSetOverlap_C", (DM, DM, PetscInt), (dm, dmSrc, overlap)); 2155 PetscFunctionReturn(0); 2156 } 2157 2158 PetscErrorCode DMPlexDistributeSetDefault_Plex(DM dm, PetscBool dist) 2159 { 2160 DM_Plex *mesh = (DM_Plex *)dm->data; 2161 2162 PetscFunctionBegin; 2163 mesh->distDefault = dist; 2164 PetscFunctionReturn(0); 2165 } 2166 2167 /*@ 2168 DMPlexDistributeSetDefault - Set flag indicating whether the DM should be distributed by default 2169 2170 Logically collective 2171 2172 Input Parameters: 2173 + dm - The DM 2174 - dist - Flag for distribution 2175 2176 Level: intermediate 2177 2178 .seealso: `DMPlexDistributeGetDefault()`, `DMPlexDistribute()` 2179 @*/ 2180 PetscErrorCode DMPlexDistributeSetDefault(DM dm, PetscBool dist) 2181 { 2182 PetscFunctionBegin; 2183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2184 PetscValidLogicalCollectiveBool(dm, dist, 2); 2185 PetscTryMethod(dm, "DMPlexDistributeSetDefault_C", (DM, PetscBool), (dm, dist)); 2186 PetscFunctionReturn(0); 2187 } 2188 2189 PetscErrorCode DMPlexDistributeGetDefault_Plex(DM dm, PetscBool *dist) 2190 { 2191 DM_Plex *mesh = (DM_Plex *)dm->data; 2192 2193 PetscFunctionBegin; 2194 *dist = mesh->distDefault; 2195 PetscFunctionReturn(0); 2196 } 2197 2198 /*@ 2199 DMPlexDistributeGetDefault - Get flag indicating whether the DM should be distributed by default 2200 2201 Not collective 2202 2203 Input Parameter: 2204 . dm - The DM 2205 2206 Output Parameter: 2207 . dist - Flag for distribution 2208 2209 Level: intermediate 2210 2211 .seealso: `DMPlexDistributeSetDefault()`, `DMPlexDistribute()` 2212 @*/ 2213 PetscErrorCode DMPlexDistributeGetDefault(DM dm, PetscBool *dist) 2214 { 2215 PetscFunctionBegin; 2216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2217 PetscValidBoolPointer(dist, 2); 2218 PetscUseMethod(dm, "DMPlexDistributeGetDefault_C", (DM, PetscBool *), (dm, dist)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@C 2223 DMPlexGetGatherDM - Get a copy of the DMPlex that gathers all points on the 2224 root process of the original's communicator. 2225 2226 Collective on dm 2227 2228 Input Parameter: 2229 . dm - the original DMPlex object 2230 2231 Output Parameters: 2232 + sf - the PetscSF used for point distribution (optional) 2233 - gatherMesh - the gathered DM object, or NULL 2234 2235 Level: intermediate 2236 2237 .seealso: `DMPlexDistribute()`, `DMPlexGetRedundantDM()` 2238 @*/ 2239 PetscErrorCode DMPlexGetGatherDM(DM dm, PetscSF *sf, DM *gatherMesh) 2240 { 2241 MPI_Comm comm; 2242 PetscMPIInt size; 2243 PetscPartitioner oldPart, gatherPart; 2244 2245 PetscFunctionBegin; 2246 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2247 PetscValidPointer(gatherMesh, 3); 2248 *gatherMesh = NULL; 2249 if (sf) *sf = NULL; 2250 comm = PetscObjectComm((PetscObject)dm); 2251 PetscCallMPI(MPI_Comm_size(comm, &size)); 2252 if (size == 1) PetscFunctionReturn(0); 2253 PetscCall(DMPlexGetPartitioner(dm, &oldPart)); 2254 PetscCall(PetscObjectReference((PetscObject)oldPart)); 2255 PetscCall(PetscPartitionerCreate(comm, &gatherPart)); 2256 PetscCall(PetscPartitionerSetType(gatherPart, PETSCPARTITIONERGATHER)); 2257 PetscCall(DMPlexSetPartitioner(dm, gatherPart)); 2258 PetscCall(DMPlexDistribute(dm, 0, sf, gatherMesh)); 2259 2260 PetscCall(DMPlexSetPartitioner(dm, oldPart)); 2261 PetscCall(PetscPartitionerDestroy(&gatherPart)); 2262 PetscCall(PetscPartitionerDestroy(&oldPart)); 2263 PetscFunctionReturn(0); 2264 } 2265 2266 /*@C 2267 DMPlexGetRedundantDM - Get a copy of the DMPlex that is completely copied on each process. 2268 2269 Collective on dm 2270 2271 Input Parameter: 2272 . dm - the original DMPlex object 2273 2274 Output Parameters: 2275 + sf - the PetscSF used for point distribution (optional) 2276 - redundantMesh - the redundant DM object, or NULL 2277 2278 Level: intermediate 2279 2280 .seealso: `DMPlexDistribute()`, `DMPlexGetGatherDM()` 2281 @*/ 2282 PetscErrorCode DMPlexGetRedundantDM(DM dm, PetscSF *sf, DM *redundantMesh) 2283 { 2284 MPI_Comm comm; 2285 PetscMPIInt size, rank; 2286 PetscInt pStart, pEnd, p; 2287 PetscInt numPoints = -1; 2288 PetscSF migrationSF, sfPoint, gatherSF; 2289 DM gatherDM, dmCoord; 2290 PetscSFNode *points; 2291 2292 PetscFunctionBegin; 2293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2294 PetscValidPointer(redundantMesh, 3); 2295 *redundantMesh = NULL; 2296 comm = PetscObjectComm((PetscObject)dm); 2297 PetscCallMPI(MPI_Comm_size(comm, &size)); 2298 if (size == 1) { 2299 PetscCall(PetscObjectReference((PetscObject)dm)); 2300 *redundantMesh = dm; 2301 if (sf) *sf = NULL; 2302 PetscFunctionReturn(0); 2303 } 2304 PetscCall(DMPlexGetGatherDM(dm, &gatherSF, &gatherDM)); 2305 if (!gatherDM) PetscFunctionReturn(0); 2306 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 2307 PetscCall(DMPlexGetChart(gatherDM, &pStart, &pEnd)); 2308 numPoints = pEnd - pStart; 2309 PetscCallMPI(MPI_Bcast(&numPoints, 1, MPIU_INT, 0, comm)); 2310 PetscCall(PetscMalloc1(numPoints, &points)); 2311 PetscCall(PetscSFCreate(comm, &migrationSF)); 2312 for (p = 0; p < numPoints; p++) { 2313 points[p].index = p; 2314 points[p].rank = 0; 2315 } 2316 PetscCall(PetscSFSetGraph(migrationSF, pEnd - pStart, numPoints, NULL, PETSC_OWN_POINTER, points, PETSC_OWN_POINTER)); 2317 PetscCall(DMPlexCreate(comm, redundantMesh)); 2318 PetscCall(PetscObjectSetName((PetscObject)*redundantMesh, "Redundant Mesh")); 2319 PetscCall(DMPlexMigrate(gatherDM, migrationSF, *redundantMesh)); 2320 /* This is to express that all point are in overlap */ 2321 PetscCall(DMPlexSetOverlap_Plex(*redundantMesh, NULL, PETSC_MAX_INT)); 2322 PetscCall(DMPlexCreatePointSF(*redundantMesh, migrationSF, PETSC_FALSE, &sfPoint)); 2323 PetscCall(DMSetPointSF(*redundantMesh, sfPoint)); 2324 PetscCall(DMGetCoordinateDM(*redundantMesh, &dmCoord)); 2325 if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint)); 2326 PetscCall(PetscSFDestroy(&sfPoint)); 2327 if (sf) { 2328 PetscSF tsf; 2329 2330 PetscCall(PetscSFCompose(gatherSF, migrationSF, &tsf)); 2331 PetscCall(DMPlexStratifyMigrationSF(dm, tsf, sf)); 2332 PetscCall(PetscSFDestroy(&tsf)); 2333 } 2334 PetscCall(PetscSFDestroy(&migrationSF)); 2335 PetscCall(PetscSFDestroy(&gatherSF)); 2336 PetscCall(DMDestroy(&gatherDM)); 2337 PetscCall(DMCopyDisc(dm, *redundantMesh)); 2338 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *redundantMesh)); 2339 PetscFunctionReturn(0); 2340 } 2341 2342 /*@ 2343 DMPlexIsDistributed - Find out whether this DM is distributed, i.e. more than one rank owns some points. 2344 2345 Collective 2346 2347 Input Parameter: 2348 . dm - The DM object 2349 2350 Output Parameter: 2351 . distributed - Flag whether the DM is distributed 2352 2353 Level: intermediate 2354 2355 Notes: 2356 This currently finds out whether at least two ranks have any DAG points. 2357 This involves MPI_Allreduce() with one integer. 2358 The result is currently not stashed so every call to this routine involves this global communication. 2359 2360 .seealso: `DMPlexDistribute()`, `DMPlexGetOverlap()`, `DMPlexIsInterpolated()` 2361 @*/ 2362 PetscErrorCode DMPlexIsDistributed(DM dm, PetscBool *distributed) 2363 { 2364 PetscInt pStart, pEnd, count; 2365 MPI_Comm comm; 2366 PetscMPIInt size; 2367 2368 PetscFunctionBegin; 2369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2370 PetscValidBoolPointer(distributed, 2); 2371 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2372 PetscCallMPI(MPI_Comm_size(comm, &size)); 2373 if (size == 1) { 2374 *distributed = PETSC_FALSE; 2375 PetscFunctionReturn(0); 2376 } 2377 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2378 count = (pEnd - pStart) > 0 ? 1 : 0; 2379 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &count, 1, MPIU_INT, MPI_SUM, comm)); 2380 *distributed = count > 1 ? PETSC_TRUE : PETSC_FALSE; 2381 PetscFunctionReturn(0); 2382 } 2383 2384 /*@C 2385 DMPlexDistributionSetName - Set the name of the specific parallel distribution 2386 2387 Input Parameters: 2388 + dm - The DM 2389 - name - The name of the specific parallel distribution 2390 2391 Note: 2392 If distribution name is set when saving, DMPlexTopologyView() saves the plex's 2393 parallel distribution (i.e., partition, ownership, and local ordering of points) under 2394 this name. Conversely, if distribution name is set when loading, DMPlexTopologyLoad() 2395 loads the parallel distribution stored in file under this name. 2396 2397 Level: developer 2398 2399 .seealso: `DMPlexDistributionGetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()` 2400 @*/ 2401 PetscErrorCode DMPlexDistributionSetName(DM dm, const char name[]) 2402 { 2403 DM_Plex *mesh = (DM_Plex *)dm->data; 2404 2405 PetscFunctionBegin; 2406 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX); 2407 if (name) PetscValidCharPointer(name, 2); 2408 PetscCall(PetscFree(mesh->distributionName)); 2409 PetscCall(PetscStrallocpy(name, &mesh->distributionName)); 2410 PetscFunctionReturn(0); 2411 } 2412 2413 /*@C 2414 DMPlexDistributionGetName - Retrieve the name of the specific parallel distribution 2415 2416 Input Parameter: 2417 . dm - The DM 2418 2419 Output Parameter: 2420 . name - The name of the specific parallel distribution 2421 2422 Note: 2423 If distribution name is set when saving, DMPlexTopologyView() saves the plex's 2424 parallel distribution (i.e., partition, ownership, and local ordering of points) under 2425 this name. Conversely, if distribution name is set when loading, DMPlexTopologyLoad() 2426 loads the parallel distribution stored in file under this name. 2427 2428 Level: developer 2429 2430 .seealso: `DMPlexDistributionSetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()` 2431 @*/ 2432 PetscErrorCode DMPlexDistributionGetName(DM dm, const char *name[]) 2433 { 2434 DM_Plex *mesh = (DM_Plex *)dm->data; 2435 2436 PetscFunctionBegin; 2437 PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX); 2438 PetscValidPointer(name, 2); 2439 *name = mesh->distributionName; 2440 PetscFunctionReturn(0); 2441 } 2442