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