1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/hashmapi.h> 3 #include <petsc/private/hashmapij.h> 4 5 const char *const DMPlexInterpolatedFlags[] = {"none", "partial", "mixed", "full", "DMPlexInterpolatedFlag", "DMPLEX_INTERPOLATED_", NULL}; 6 7 /* HashIJKL */ 8 9 #include <petsc/private/hashmap.h> 10 11 typedef struct _PetscHashIJKLKey { 12 PetscInt i, j, k, l; 13 } PetscHashIJKLKey; 14 15 #define PetscHashIJKLKeyHash(key) PetscHashCombine(PetscHashCombine(PetscHashInt((key).i), PetscHashInt((key).j)), PetscHashCombine(PetscHashInt((key).k), PetscHashInt((key).l))) 16 17 #define PetscHashIJKLKeyEqual(k1, k2) (((k1).i == (k2).i) ? ((k1).j == (k2).j) ? ((k1).k == (k2).k) ? ((k1).l == (k2).l) : 0 : 0 : 0) 18 19 PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PETSC_HASH_MAP(HashIJKL, PetscHashIJKLKey, PetscInt, PetscHashIJKLKeyHash, PetscHashIJKLKeyEqual, -1)) 20 21 static PetscSFNode _PetscInvalidSFNode = {-1, -1}; 22 23 typedef struct _PetscHashIJKLRemoteKey { 24 PetscSFNode i, j, k, l; 25 } PetscHashIJKLRemoteKey; 26 27 #define PetscHashIJKLRemoteKeyHash(key) \ 28 PetscHashCombine(PetscHashCombine(PetscHashInt((key).i.rank + (key).i.index), PetscHashInt((key).j.rank + (key).j.index)), PetscHashCombine(PetscHashInt((key).k.rank + (key).k.index), PetscHashInt((key).l.rank + (key).l.index))) 29 30 #define PetscHashIJKLRemoteKeyEqual(k1, k2) \ 31 (((k1).i.rank == (k2).i.rank) ? ((k1).i.index == (k2).i.index) ? ((k1).j.rank == (k2).j.rank) ? ((k1).j.index == (k2).j.index) ? ((k1).k.rank == (k2).k.rank) ? ((k1).k.index == (k2).k.index) ? ((k1).l.rank == (k2).l.rank) ? ((k1).l.index == (k2).l.index) : 0 : 0 : 0 : 0 : 0 : 0 : 0) 32 33 PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PETSC_HASH_MAP(HashIJKLRemote, PetscHashIJKLRemoteKey, PetscSFNode, PetscHashIJKLRemoteKeyHash, PetscHashIJKLRemoteKeyEqual, _PetscInvalidSFNode)) 34 35 static PetscErrorCode PetscSortSFNode(PetscInt n, PetscSFNode A[]) { 36 PetscInt i; 37 38 PetscFunctionBegin; 39 for (i = 1; i < n; ++i) { 40 PetscSFNode x = A[i]; 41 PetscInt j; 42 43 for (j = i - 1; j >= 0; --j) { 44 if ((A[j].rank > x.rank) || (A[j].rank == x.rank && A[j].index > x.index)) break; 45 A[j + 1] = A[j]; 46 } 47 A[j + 1] = x; 48 } 49 PetscFunctionReturn(0); 50 } 51 52 /* 53 DMPlexGetRawFaces_Internal - Gets groups of vertices that correspond to faces for the given cone 54 */ 55 PetscErrorCode DMPlexGetRawFaces_Internal(DM dm, DMPolytopeType ct, const PetscInt cone[], PetscInt *numFaces, const DMPolytopeType *faceTypes[], const PetscInt *faceSizes[], const PetscInt *faces[]) { 56 DMPolytopeType *typesTmp; 57 PetscInt *sizesTmp, *facesTmp; 58 PetscInt maxConeSize, maxSupportSize; 59 60 PetscFunctionBegin; 61 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 62 if (cone) PetscValidIntPointer(cone, 3); 63 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 64 if (faceTypes) PetscCall(DMGetWorkArray(dm, PetscMax(maxConeSize, maxSupportSize), MPIU_INT, &typesTmp)); 65 if (faceSizes) PetscCall(DMGetWorkArray(dm, PetscMax(maxConeSize, maxSupportSize), MPIU_INT, &sizesTmp)); 66 if (faces) PetscCall(DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp)); 67 switch (ct) { 68 case DM_POLYTOPE_POINT: 69 if (numFaces) *numFaces = 0; 70 break; 71 case DM_POLYTOPE_SEGMENT: 72 if (numFaces) *numFaces = 2; 73 if (faceTypes) { 74 typesTmp[0] = DM_POLYTOPE_POINT; 75 typesTmp[1] = DM_POLYTOPE_POINT; 76 *faceTypes = typesTmp; 77 } 78 if (faceSizes) { 79 sizesTmp[0] = 1; 80 sizesTmp[1] = 1; 81 *faceSizes = sizesTmp; 82 } 83 if (faces) { 84 facesTmp[0] = cone[0]; 85 facesTmp[1] = cone[1]; 86 *faces = facesTmp; 87 } 88 break; 89 case DM_POLYTOPE_POINT_PRISM_TENSOR: 90 if (numFaces) *numFaces = 2; 91 if (faceTypes) { 92 typesTmp[0] = DM_POLYTOPE_POINT; 93 typesTmp[1] = DM_POLYTOPE_POINT; 94 *faceTypes = typesTmp; 95 } 96 if (faceSizes) { 97 sizesTmp[0] = 1; 98 sizesTmp[1] = 1; 99 *faceSizes = sizesTmp; 100 } 101 if (faces) { 102 facesTmp[0] = cone[0]; 103 facesTmp[1] = cone[1]; 104 *faces = facesTmp; 105 } 106 break; 107 case DM_POLYTOPE_TRIANGLE: 108 if (numFaces) *numFaces = 3; 109 if (faceTypes) { 110 typesTmp[0] = DM_POLYTOPE_SEGMENT; 111 typesTmp[1] = DM_POLYTOPE_SEGMENT; 112 typesTmp[2] = DM_POLYTOPE_SEGMENT; 113 *faceTypes = typesTmp; 114 } 115 if (faceSizes) { 116 sizesTmp[0] = 2; 117 sizesTmp[1] = 2; 118 sizesTmp[2] = 2; 119 *faceSizes = sizesTmp; 120 } 121 if (faces) { 122 facesTmp[0] = cone[0]; 123 facesTmp[1] = cone[1]; 124 facesTmp[2] = cone[1]; 125 facesTmp[3] = cone[2]; 126 facesTmp[4] = cone[2]; 127 facesTmp[5] = cone[0]; 128 *faces = facesTmp; 129 } 130 break; 131 case DM_POLYTOPE_QUADRILATERAL: 132 /* Vertices follow right hand rule */ 133 if (numFaces) *numFaces = 4; 134 if (faceTypes) { 135 typesTmp[0] = DM_POLYTOPE_SEGMENT; 136 typesTmp[1] = DM_POLYTOPE_SEGMENT; 137 typesTmp[2] = DM_POLYTOPE_SEGMENT; 138 typesTmp[3] = DM_POLYTOPE_SEGMENT; 139 *faceTypes = typesTmp; 140 } 141 if (faceSizes) { 142 sizesTmp[0] = 2; 143 sizesTmp[1] = 2; 144 sizesTmp[2] = 2; 145 sizesTmp[3] = 2; 146 *faceSizes = sizesTmp; 147 } 148 if (faces) { 149 facesTmp[0] = cone[0]; 150 facesTmp[1] = cone[1]; 151 facesTmp[2] = cone[1]; 152 facesTmp[3] = cone[2]; 153 facesTmp[4] = cone[2]; 154 facesTmp[5] = cone[3]; 155 facesTmp[6] = cone[3]; 156 facesTmp[7] = cone[0]; 157 *faces = facesTmp; 158 } 159 break; 160 case DM_POLYTOPE_SEG_PRISM_TENSOR: 161 if (numFaces) *numFaces = 4; 162 if (faceTypes) { 163 typesTmp[0] = DM_POLYTOPE_SEGMENT; 164 typesTmp[1] = DM_POLYTOPE_SEGMENT; 165 typesTmp[2] = DM_POLYTOPE_POINT_PRISM_TENSOR; 166 typesTmp[3] = DM_POLYTOPE_POINT_PRISM_TENSOR; 167 *faceTypes = typesTmp; 168 } 169 if (faceSizes) { 170 sizesTmp[0] = 2; 171 sizesTmp[1] = 2; 172 sizesTmp[2] = 2; 173 sizesTmp[3] = 2; 174 *faceSizes = sizesTmp; 175 } 176 if (faces) { 177 facesTmp[0] = cone[0]; 178 facesTmp[1] = cone[1]; 179 facesTmp[2] = cone[2]; 180 facesTmp[3] = cone[3]; 181 facesTmp[4] = cone[0]; 182 facesTmp[5] = cone[2]; 183 facesTmp[6] = cone[1]; 184 facesTmp[7] = cone[3]; 185 *faces = facesTmp; 186 } 187 break; 188 case DM_POLYTOPE_TETRAHEDRON: 189 /* Vertices of first face follow right hand rule and normal points away from last vertex */ 190 if (numFaces) *numFaces = 4; 191 if (faceTypes) { 192 typesTmp[0] = DM_POLYTOPE_TRIANGLE; 193 typesTmp[1] = DM_POLYTOPE_TRIANGLE; 194 typesTmp[2] = DM_POLYTOPE_TRIANGLE; 195 typesTmp[3] = DM_POLYTOPE_TRIANGLE; 196 *faceTypes = typesTmp; 197 } 198 if (faceSizes) { 199 sizesTmp[0] = 3; 200 sizesTmp[1] = 3; 201 sizesTmp[2] = 3; 202 sizesTmp[3] = 3; 203 *faceSizes = sizesTmp; 204 } 205 if (faces) { 206 facesTmp[0] = cone[0]; 207 facesTmp[1] = cone[1]; 208 facesTmp[2] = cone[2]; 209 facesTmp[3] = cone[0]; 210 facesTmp[4] = cone[3]; 211 facesTmp[5] = cone[1]; 212 facesTmp[6] = cone[0]; 213 facesTmp[7] = cone[2]; 214 facesTmp[8] = cone[3]; 215 facesTmp[9] = cone[2]; 216 facesTmp[10] = cone[1]; 217 facesTmp[11] = cone[3]; 218 *faces = facesTmp; 219 } 220 break; 221 case DM_POLYTOPE_HEXAHEDRON: 222 /* 7--------6 223 /| /| 224 / | / | 225 4--------5 | 226 | | | | 227 | | | | 228 | 1--------2 229 | / | / 230 |/ |/ 231 0--------3 232 */ 233 if (numFaces) *numFaces = 6; 234 if (faceTypes) { 235 typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; 236 typesTmp[1] = DM_POLYTOPE_QUADRILATERAL; 237 typesTmp[2] = DM_POLYTOPE_QUADRILATERAL; 238 typesTmp[3] = DM_POLYTOPE_QUADRILATERAL; 239 typesTmp[4] = DM_POLYTOPE_QUADRILATERAL; 240 typesTmp[5] = DM_POLYTOPE_QUADRILATERAL; 241 *faceTypes = typesTmp; 242 } 243 if (faceSizes) { 244 sizesTmp[0] = 4; 245 sizesTmp[1] = 4; 246 sizesTmp[2] = 4; 247 sizesTmp[3] = 4; 248 sizesTmp[4] = 4; 249 sizesTmp[5] = 4; 250 *faceSizes = sizesTmp; 251 } 252 if (faces) { 253 facesTmp[0] = cone[0]; 254 facesTmp[1] = cone[1]; 255 facesTmp[2] = cone[2]; 256 facesTmp[3] = cone[3]; /* Bottom */ 257 facesTmp[4] = cone[4]; 258 facesTmp[5] = cone[5]; 259 facesTmp[6] = cone[6]; 260 facesTmp[7] = cone[7]; /* Top */ 261 facesTmp[8] = cone[0]; 262 facesTmp[9] = cone[3]; 263 facesTmp[10] = cone[5]; 264 facesTmp[11] = cone[4]; /* Front */ 265 facesTmp[12] = cone[2]; 266 facesTmp[13] = cone[1]; 267 facesTmp[14] = cone[7]; 268 facesTmp[15] = cone[6]; /* Back */ 269 facesTmp[16] = cone[3]; 270 facesTmp[17] = cone[2]; 271 facesTmp[18] = cone[6]; 272 facesTmp[19] = cone[5]; /* Right */ 273 facesTmp[20] = cone[0]; 274 facesTmp[21] = cone[4]; 275 facesTmp[22] = cone[7]; 276 facesTmp[23] = cone[1]; /* Left */ 277 *faces = facesTmp; 278 } 279 break; 280 case DM_POLYTOPE_TRI_PRISM: 281 if (numFaces) *numFaces = 5; 282 if (faceTypes) { 283 typesTmp[0] = DM_POLYTOPE_TRIANGLE; 284 typesTmp[1] = DM_POLYTOPE_TRIANGLE; 285 typesTmp[2] = DM_POLYTOPE_QUADRILATERAL; 286 typesTmp[3] = DM_POLYTOPE_QUADRILATERAL; 287 typesTmp[4] = DM_POLYTOPE_QUADRILATERAL; 288 *faceTypes = typesTmp; 289 } 290 if (faceSizes) { 291 sizesTmp[0] = 3; 292 sizesTmp[1] = 3; 293 sizesTmp[2] = 4; 294 sizesTmp[3] = 4; 295 sizesTmp[4] = 4; 296 *faceSizes = sizesTmp; 297 } 298 if (faces) { 299 facesTmp[0] = cone[0]; 300 facesTmp[1] = cone[1]; 301 facesTmp[2] = cone[2]; /* Bottom */ 302 facesTmp[3] = cone[3]; 303 facesTmp[4] = cone[4]; 304 facesTmp[5] = cone[5]; /* Top */ 305 facesTmp[6] = cone[0]; 306 facesTmp[7] = cone[2]; 307 facesTmp[8] = cone[4]; 308 facesTmp[9] = cone[3]; /* Back left */ 309 facesTmp[10] = cone[2]; 310 facesTmp[11] = cone[1]; 311 facesTmp[12] = cone[5]; 312 facesTmp[13] = cone[4]; /* Front */ 313 facesTmp[14] = cone[1]; 314 facesTmp[15] = cone[0]; 315 facesTmp[16] = cone[3]; 316 facesTmp[17] = cone[5]; /* Back right */ 317 *faces = facesTmp; 318 } 319 break; 320 case DM_POLYTOPE_TRI_PRISM_TENSOR: 321 if (numFaces) *numFaces = 5; 322 if (faceTypes) { 323 typesTmp[0] = DM_POLYTOPE_TRIANGLE; 324 typesTmp[1] = DM_POLYTOPE_TRIANGLE; 325 typesTmp[2] = DM_POLYTOPE_SEG_PRISM_TENSOR; 326 typesTmp[3] = DM_POLYTOPE_SEG_PRISM_TENSOR; 327 typesTmp[4] = DM_POLYTOPE_SEG_PRISM_TENSOR; 328 *faceTypes = typesTmp; 329 } 330 if (faceSizes) { 331 sizesTmp[0] = 3; 332 sizesTmp[1] = 3; 333 sizesTmp[2] = 4; 334 sizesTmp[3] = 4; 335 sizesTmp[4] = 4; 336 *faceSizes = sizesTmp; 337 } 338 if (faces) { 339 facesTmp[0] = cone[0]; 340 facesTmp[1] = cone[1]; 341 facesTmp[2] = cone[2]; /* Bottom */ 342 facesTmp[3] = cone[3]; 343 facesTmp[4] = cone[4]; 344 facesTmp[5] = cone[5]; /* Top */ 345 facesTmp[6] = cone[0]; 346 facesTmp[7] = cone[1]; 347 facesTmp[8] = cone[3]; 348 facesTmp[9] = cone[4]; /* Back left */ 349 facesTmp[10] = cone[1]; 350 facesTmp[11] = cone[2]; 351 facesTmp[12] = cone[4]; 352 facesTmp[13] = cone[5]; /* Back right */ 353 facesTmp[14] = cone[2]; 354 facesTmp[15] = cone[0]; 355 facesTmp[16] = cone[5]; 356 facesTmp[17] = cone[3]; /* Front */ 357 *faces = facesTmp; 358 } 359 break; 360 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 361 /* 7--------6 362 /| /| 363 / | / | 364 4--------5 | 365 | | | | 366 | | | | 367 | 3--------2 368 | / | / 369 |/ |/ 370 0--------1 371 */ 372 if (numFaces) *numFaces = 6; 373 if (faceTypes) { 374 typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; 375 typesTmp[1] = DM_POLYTOPE_QUADRILATERAL; 376 typesTmp[2] = DM_POLYTOPE_SEG_PRISM_TENSOR; 377 typesTmp[3] = DM_POLYTOPE_SEG_PRISM_TENSOR; 378 typesTmp[4] = DM_POLYTOPE_SEG_PRISM_TENSOR; 379 typesTmp[5] = DM_POLYTOPE_SEG_PRISM_TENSOR; 380 *faceTypes = typesTmp; 381 } 382 if (faceSizes) { 383 sizesTmp[0] = 4; 384 sizesTmp[1] = 4; 385 sizesTmp[2] = 4; 386 sizesTmp[3] = 4; 387 sizesTmp[4] = 4; 388 sizesTmp[5] = 4; 389 *faceSizes = sizesTmp; 390 } 391 if (faces) { 392 facesTmp[0] = cone[0]; 393 facesTmp[1] = cone[1]; 394 facesTmp[2] = cone[2]; 395 facesTmp[3] = cone[3]; /* Bottom */ 396 facesTmp[4] = cone[4]; 397 facesTmp[5] = cone[5]; 398 facesTmp[6] = cone[6]; 399 facesTmp[7] = cone[7]; /* Top */ 400 facesTmp[8] = cone[0]; 401 facesTmp[9] = cone[1]; 402 facesTmp[10] = cone[4]; 403 facesTmp[11] = cone[5]; /* Front */ 404 facesTmp[12] = cone[1]; 405 facesTmp[13] = cone[2]; 406 facesTmp[14] = cone[5]; 407 facesTmp[15] = cone[6]; /* Right */ 408 facesTmp[16] = cone[2]; 409 facesTmp[17] = cone[3]; 410 facesTmp[18] = cone[6]; 411 facesTmp[19] = cone[7]; /* Back */ 412 facesTmp[20] = cone[3]; 413 facesTmp[21] = cone[0]; 414 facesTmp[22] = cone[7]; 415 facesTmp[23] = cone[4]; /* Left */ 416 *faces = facesTmp; 417 } 418 break; 419 case DM_POLYTOPE_PYRAMID: 420 /* 421 4---- 422 |\-\ \----- 423 | \ -\ \ 424 | 1--\-----2 425 | / \ / 426 |/ \ / 427 0--------3 428 */ 429 if (numFaces) *numFaces = 5; 430 if (faceTypes) { 431 typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; 432 typesTmp[1] = DM_POLYTOPE_TRIANGLE; 433 typesTmp[2] = DM_POLYTOPE_TRIANGLE; 434 typesTmp[3] = DM_POLYTOPE_TRIANGLE; 435 typesTmp[4] = DM_POLYTOPE_TRIANGLE; 436 *faceTypes = typesTmp; 437 } 438 if (faceSizes) { 439 sizesTmp[0] = 4; 440 sizesTmp[1] = 3; 441 sizesTmp[2] = 3; 442 sizesTmp[3] = 3; 443 sizesTmp[4] = 3; 444 *faceSizes = sizesTmp; 445 } 446 if (faces) { 447 facesTmp[0] = cone[0]; 448 facesTmp[1] = cone[1]; 449 facesTmp[2] = cone[2]; 450 facesTmp[3] = cone[3]; /* Bottom */ 451 facesTmp[4] = cone[0]; 452 facesTmp[5] = cone[3]; 453 facesTmp[6] = cone[4]; /* Front */ 454 facesTmp[7] = cone[3]; 455 facesTmp[8] = cone[2]; 456 facesTmp[9] = cone[4]; /* Right */ 457 facesTmp[10] = cone[2]; 458 facesTmp[11] = cone[1]; 459 facesTmp[12] = cone[4]; /* Back */ 460 facesTmp[13] = cone[1]; 461 facesTmp[14] = cone[0]; 462 facesTmp[15] = cone[4]; /* Left */ 463 *faces = facesTmp; 464 } 465 break; 466 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No face description for cell type %s", DMPolytopeTypes[ct]); 467 } 468 PetscFunctionReturn(0); 469 } 470 471 PetscErrorCode DMPlexRestoreRawFaces_Internal(DM dm, DMPolytopeType ct, const PetscInt cone[], PetscInt *numFaces, const DMPolytopeType *faceTypes[], const PetscInt *faceSizes[], const PetscInt *faces[]) { 472 PetscFunctionBegin; 473 if (faceTypes) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)faceTypes)); 474 if (faceSizes) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)faceSizes)); 475 if (faces) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)faces)); 476 PetscFunctionReturn(0); 477 } 478 479 /* This interpolates faces for cells at some stratum */ 480 static PetscErrorCode DMPlexInterpolateFaces_Internal(DM dm, PetscInt cellDepth, DM idm) { 481 DMLabel ctLabel; 482 PetscHashIJKL faceTable; 483 PetscInt faceTypeNum[DM_NUM_POLYTOPES]; 484 PetscInt depth, d, pStart, Np, cStart, cEnd, c, fStart, fEnd; 485 486 PetscFunctionBegin; 487 PetscCall(DMPlexGetDepth(dm, &depth)); 488 PetscCall(PetscHashIJKLCreate(&faceTable)); 489 PetscCall(PetscArrayzero(faceTypeNum, DM_NUM_POLYTOPES)); 490 PetscCall(DMPlexGetDepthStratum(dm, cellDepth, &cStart, &cEnd)); 491 /* Number new faces and save face vertices in hash table */ 492 PetscCall(DMPlexGetDepthStratum(dm, depth > cellDepth ? cellDepth : 0, NULL, &fStart)); 493 fEnd = fStart; 494 for (c = cStart; c < cEnd; ++c) { 495 const PetscInt *cone, *faceSizes, *faces; 496 const DMPolytopeType *faceTypes; 497 DMPolytopeType ct; 498 PetscInt numFaces, cf, foff = 0; 499 500 PetscCall(DMPlexGetCellType(dm, c, &ct)); 501 PetscCall(DMPlexGetCone(dm, c, &cone)); 502 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 503 for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 504 const PetscInt faceSize = faceSizes[cf]; 505 const DMPolytopeType faceType = faceTypes[cf]; 506 const PetscInt *face = &faces[foff]; 507 PetscHashIJKLKey key; 508 PetscHashIter iter; 509 PetscBool missing; 510 511 PetscCheck(faceSize <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 512 key.i = face[0]; 513 key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 514 key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 515 key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 516 PetscCall(PetscSortInt(faceSize, (PetscInt *)&key)); 517 PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 518 if (missing) { 519 PetscCall(PetscHashIJKLIterSet(faceTable, iter, fEnd++)); 520 ++faceTypeNum[faceType]; 521 } 522 } 523 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 524 } 525 /* We need to number faces contiguously among types */ 526 { 527 PetscInt faceTypeStart[DM_NUM_POLYTOPES], ct, numFT = 0; 528 529 for (ct = 0; ct < DM_NUM_POLYTOPES; ++ct) { 530 if (faceTypeNum[ct]) ++numFT; 531 faceTypeStart[ct] = 0; 532 } 533 if (numFT > 1) { 534 PetscCall(PetscHashIJKLClear(faceTable)); 535 faceTypeStart[0] = fStart; 536 for (ct = 1; ct < DM_NUM_POLYTOPES; ++ct) faceTypeStart[ct] = faceTypeStart[ct - 1] + faceTypeNum[ct - 1]; 537 for (c = cStart; c < cEnd; ++c) { 538 const PetscInt *cone, *faceSizes, *faces; 539 const DMPolytopeType *faceTypes; 540 DMPolytopeType ct; 541 PetscInt numFaces, cf, foff = 0; 542 543 PetscCall(DMPlexGetCellType(dm, c, &ct)); 544 PetscCall(DMPlexGetCone(dm, c, &cone)); 545 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 546 for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 547 const PetscInt faceSize = faceSizes[cf]; 548 const DMPolytopeType faceType = faceTypes[cf]; 549 const PetscInt *face = &faces[foff]; 550 PetscHashIJKLKey key; 551 PetscHashIter iter; 552 PetscBool missing; 553 554 PetscCheck(faceSize <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 555 key.i = face[0]; 556 key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 557 key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 558 key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 559 PetscCall(PetscSortInt(faceSize, (PetscInt *)&key)); 560 PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 561 if (missing) PetscCall(PetscHashIJKLIterSet(faceTable, iter, faceTypeStart[faceType]++)); 562 } 563 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 564 } 565 for (ct = 1; ct < DM_NUM_POLYTOPES; ++ct) { 566 PetscCheck(faceTypeStart[ct] == faceTypeStart[ct - 1] + faceTypeNum[ct], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent numbering for cell type %s, %" PetscInt_FMT " != %" PetscInt_FMT " + %" PetscInt_FMT, DMPolytopeTypes[ct], faceTypeStart[ct], faceTypeStart[ct - 1], faceTypeNum[ct]); 567 } 568 } 569 } 570 /* Add new points, always at the end of the numbering */ 571 PetscCall(DMPlexGetChart(dm, &pStart, &Np)); 572 PetscCall(DMPlexSetChart(idm, pStart, Np + (fEnd - fStart))); 573 /* Set cone sizes */ 574 /* Must create the celltype label here so that we do not automatically try to compute the types */ 575 PetscCall(DMCreateLabel(idm, "celltype")); 576 PetscCall(DMPlexGetCellTypeLabel(idm, &ctLabel)); 577 for (d = 0; d <= depth; ++d) { 578 DMPolytopeType ct; 579 PetscInt coneSize, pStart, pEnd, p; 580 581 if (d == cellDepth) continue; 582 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 583 for (p = pStart; p < pEnd; ++p) { 584 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 585 PetscCall(DMPlexSetConeSize(idm, p, coneSize)); 586 PetscCall(DMPlexGetCellType(dm, p, &ct)); 587 PetscCall(DMPlexSetCellType(idm, p, ct)); 588 } 589 } 590 for (c = cStart; c < cEnd; ++c) { 591 const PetscInt *cone, *faceSizes, *faces; 592 const DMPolytopeType *faceTypes; 593 DMPolytopeType ct; 594 PetscInt numFaces, cf, foff = 0; 595 596 PetscCall(DMPlexGetCellType(dm, c, &ct)); 597 PetscCall(DMPlexGetCone(dm, c, &cone)); 598 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 599 PetscCall(DMPlexSetCellType(idm, c, ct)); 600 PetscCall(DMPlexSetConeSize(idm, c, numFaces)); 601 for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 602 const PetscInt faceSize = faceSizes[cf]; 603 const DMPolytopeType faceType = faceTypes[cf]; 604 const PetscInt *face = &faces[foff]; 605 PetscHashIJKLKey key; 606 PetscHashIter iter; 607 PetscBool missing; 608 PetscInt f; 609 610 PetscCheck(faceSize <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 611 key.i = face[0]; 612 key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 613 key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 614 key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 615 PetscCall(PetscSortInt(faceSize, (PetscInt *)&key)); 616 PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 617 PetscCheck(!missing, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing face (cell %" PetscInt_FMT ", lf %" PetscInt_FMT ")", c, cf); 618 PetscCall(PetscHashIJKLIterGet(faceTable, iter, &f)); 619 PetscCall(DMPlexSetConeSize(idm, f, faceSize)); 620 PetscCall(DMPlexSetCellType(idm, f, faceType)); 621 } 622 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 623 } 624 PetscCall(DMSetUp(idm)); 625 /* Initialize cones so we do not need the bash table to tell us that a cone has been set */ 626 { 627 PetscSection cs; 628 PetscInt *cones, csize; 629 630 PetscCall(DMPlexGetConeSection(idm, &cs)); 631 PetscCall(DMPlexGetCones(idm, &cones)); 632 PetscCall(PetscSectionGetStorageSize(cs, &csize)); 633 for (c = 0; c < csize; ++c) cones[c] = -1; 634 } 635 /* Set cones */ 636 for (d = 0; d <= depth; ++d) { 637 const PetscInt *cone; 638 PetscInt pStart, pEnd, p; 639 640 if (d == cellDepth) continue; 641 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 642 for (p = pStart; p < pEnd; ++p) { 643 PetscCall(DMPlexGetCone(dm, p, &cone)); 644 PetscCall(DMPlexSetCone(idm, p, cone)); 645 PetscCall(DMPlexGetConeOrientation(dm, p, &cone)); 646 PetscCall(DMPlexSetConeOrientation(idm, p, cone)); 647 } 648 } 649 for (c = cStart; c < cEnd; ++c) { 650 const PetscInt *cone, *faceSizes, *faces; 651 const DMPolytopeType *faceTypes; 652 DMPolytopeType ct; 653 PetscInt numFaces, cf, foff = 0; 654 655 PetscCall(DMPlexGetCellType(dm, c, &ct)); 656 PetscCall(DMPlexGetCone(dm, c, &cone)); 657 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 658 for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 659 DMPolytopeType faceType = faceTypes[cf]; 660 const PetscInt faceSize = faceSizes[cf]; 661 const PetscInt *face = &faces[foff]; 662 const PetscInt *fcone; 663 PetscHashIJKLKey key; 664 PetscHashIter iter; 665 PetscBool missing; 666 PetscInt f; 667 668 PetscCheck(faceSize <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 669 key.i = face[0]; 670 key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 671 key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 672 key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 673 PetscCall(PetscSortInt(faceSize, (PetscInt *)&key)); 674 PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 675 PetscCall(PetscHashIJKLIterGet(faceTable, iter, &f)); 676 PetscCall(DMPlexInsertCone(idm, c, cf, f)); 677 PetscCall(DMPlexGetCone(idm, f, &fcone)); 678 if (fcone[0] < 0) PetscCall(DMPlexSetCone(idm, f, face)); 679 { 680 const PetscInt *cone; 681 PetscInt coneSize, ornt; 682 683 PetscCall(DMPlexGetConeSize(idm, f, &coneSize)); 684 PetscCall(DMPlexGetCone(idm, f, &cone)); 685 PetscCheck(coneSize == faceSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %" PetscInt_FMT " for face %" PetscInt_FMT " should be %" PetscInt_FMT, coneSize, f, faceSize); 686 /* Notice that we have to use vertices here because the lower dimensional faces have not been created yet */ 687 PetscCall(DMPolytopeGetVertexOrientation(faceType, cone, face, &ornt)); 688 PetscCall(DMPlexInsertConeOrientation(idm, c, cf, ornt)); 689 } 690 } 691 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 692 } 693 PetscCall(PetscHashIJKLDestroy(&faceTable)); 694 PetscCall(DMPlexSymmetrize(idm)); 695 PetscCall(DMPlexStratify(idm)); 696 PetscFunctionReturn(0); 697 } 698 699 static PetscErrorCode SortRmineRremoteByRemote_Private(PetscSF sf, PetscInt *rmine1[], PetscInt *rremote1[]) { 700 PetscInt nleaves; 701 PetscInt nranks; 702 const PetscMPIInt *ranks = NULL; 703 const PetscInt *roffset = NULL, *rmine = NULL, *rremote = NULL; 704 PetscInt n, o, r; 705 706 PetscFunctionBegin; 707 PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, &rmine, &rremote)); 708 nleaves = roffset[nranks]; 709 PetscCall(PetscMalloc2(nleaves, rmine1, nleaves, rremote1)); 710 for (r = 0; r < nranks; r++) { 711 /* simultaneously sort rank-wise portions of rmine & rremote by values in rremote 712 - to unify order with the other side */ 713 o = roffset[r]; 714 n = roffset[r + 1] - o; 715 PetscCall(PetscArraycpy(&(*rmine1)[o], &rmine[o], n)); 716 PetscCall(PetscArraycpy(&(*rremote1)[o], &rremote[o], n)); 717 PetscCall(PetscSortIntWithArray(n, &(*rremote1)[o], &(*rmine1)[o])); 718 } 719 PetscFunctionReturn(0); 720 } 721 722 PetscErrorCode DMPlexOrientInterface_Internal(DM dm) { 723 PetscSF sf; 724 const PetscInt *locals; 725 const PetscSFNode *remotes; 726 const PetscMPIInt *ranks; 727 const PetscInt *roffset; 728 PetscInt *rmine1, *rremote1; /* rmine and rremote copies simultaneously sorted by rank and rremote */ 729 PetscInt nroots, p, nleaves, nranks, r, maxConeSize = 0; 730 PetscInt(*roots)[4], (*leaves)[4], mainCone[4]; 731 PetscMPIInt(*rootsRanks)[4], (*leavesRanks)[4]; 732 MPI_Comm comm; 733 PetscMPIInt rank, size; 734 PetscInt debug = 0; 735 736 PetscFunctionBegin; 737 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 738 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 739 PetscCallMPI(MPI_Comm_size(comm, &size)); 740 PetscCall(DMGetPointSF(dm, &sf)); 741 PetscCall(DMViewFromOptions(dm, NULL, "-before_orient_interface_dm_view")); 742 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 743 PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &locals, &remotes)); 744 if (nroots < 0) PetscFunctionReturn(0); 745 PetscCall(PetscSFSetUp(sf)); 746 PetscCall(SortRmineRremoteByRemote_Private(sf, &rmine1, &rremote1)); 747 for (p = 0; p < nleaves; ++p) { 748 PetscInt coneSize; 749 PetscCall(DMPlexGetConeSize(dm, locals[p], &coneSize)); 750 maxConeSize = PetscMax(maxConeSize, coneSize); 751 } 752 PetscCheck(maxConeSize <= 4, comm, PETSC_ERR_SUP, "This method does not support cones of size %" PetscInt_FMT, maxConeSize); 753 PetscCall(PetscMalloc4(nroots, &roots, nroots, &leaves, nroots, &rootsRanks, nroots, &leavesRanks)); 754 for (p = 0; p < nroots; ++p) { 755 const PetscInt *cone; 756 PetscInt coneSize, c, ind0; 757 758 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 759 PetscCall(DMPlexGetCone(dm, p, &cone)); 760 /* Ignore vertices */ 761 if (coneSize < 2) { 762 for (c = 0; c < 4; c++) { 763 roots[p][c] = -1; 764 rootsRanks[p][c] = -1; 765 } 766 continue; 767 } 768 /* Translate all points to root numbering */ 769 for (c = 0; c < PetscMin(coneSize, 4); c++) { 770 PetscCall(PetscFindInt(cone[c], nleaves, locals, &ind0)); 771 if (ind0 < 0) { 772 roots[p][c] = cone[c]; 773 rootsRanks[p][c] = rank; 774 } else { 775 roots[p][c] = remotes[ind0].index; 776 rootsRanks[p][c] = remotes[ind0].rank; 777 } 778 } 779 for (c = coneSize; c < 4; c++) { 780 roots[p][c] = -1; 781 rootsRanks[p][c] = -1; 782 } 783 } 784 for (p = 0; p < nroots; ++p) { 785 PetscInt c; 786 for (c = 0; c < 4; c++) { 787 leaves[p][c] = -2; 788 leavesRanks[p][c] = -2; 789 } 790 } 791 PetscCall(PetscSFBcastBegin(sf, MPIU_4INT, roots, leaves, MPI_REPLACE)); 792 PetscCall(PetscSFBcastBegin(sf, MPI_4INT, rootsRanks, leavesRanks, MPI_REPLACE)); 793 PetscCall(PetscSFBcastEnd(sf, MPIU_4INT, roots, leaves, MPI_REPLACE)); 794 PetscCall(PetscSFBcastEnd(sf, MPI_4INT, rootsRanks, leavesRanks, MPI_REPLACE)); 795 if (debug) { 796 PetscCall(PetscSynchronizedFlush(comm, NULL)); 797 if (rank == 0) PetscCall(PetscSynchronizedPrintf(comm, "Referenced roots\n")); 798 } 799 PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, NULL, NULL)); 800 for (p = 0; p < nroots; ++p) { 801 DMPolytopeType ct; 802 const PetscInt *cone; 803 PetscInt coneSize, c, ind0, o; 804 805 if (leaves[p][0] < 0) continue; /* Ignore vertices */ 806 PetscCall(DMPlexGetCellType(dm, p, &ct)); 807 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 808 PetscCall(DMPlexGetCone(dm, p, &cone)); 809 if (debug) { 810 PetscCall(PetscSynchronizedPrintf(comm, "[%d] %4" PetscInt_FMT ": cone=[%4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT "] roots=[(%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ")] leaves=[(%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ")]", rank, p, cone[0], cone[1], cone[2], cone[3], rootsRanks[p][0], roots[p][0], rootsRanks[p][1], roots[p][1], rootsRanks[p][2], roots[p][2], rootsRanks[p][3], roots[p][3], leavesRanks[p][0], leaves[p][0], leavesRanks[p][1], leaves[p][1], leavesRanks[p][2], leaves[p][2], leavesRanks[p][3], leaves[p][3])); 811 } 812 if (leavesRanks[p][0] != rootsRanks[p][0] || leaves[p][0] != roots[p][0] || leavesRanks[p][1] != rootsRanks[p][1] || leaves[p][1] != roots[p][1] || leavesRanks[p][2] != rootsRanks[p][2] || leaves[p][2] != roots[p][2] || leavesRanks[p][3] != rootsRanks[p][3] || leaves[p][3] != roots[p][3]) { 813 /* Translate these leaves to my cone points; mainCone means desired order p's cone points */ 814 for (c = 0; c < PetscMin(coneSize, 4); ++c) { 815 PetscInt rS, rN; 816 817 if (leavesRanks[p][c] == rank) { 818 /* A local leaf is just taken as it is */ 819 mainCone[c] = leaves[p][c]; 820 continue; 821 } 822 /* Find index of rank leavesRanks[p][c] among remote ranks */ 823 /* No need for PetscMPIIntCast because these integers were originally cast from PetscMPIInt. */ 824 PetscCall(PetscFindMPIInt((PetscMPIInt)leavesRanks[p][c], nranks, ranks, &r)); 825 PetscCheck(r >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " cone[%" PetscInt_FMT "]=%" PetscInt_FMT " root (%d,%" PetscInt_FMT ") leaf (%d,%" PetscInt_FMT "): leaf rank not found among remote ranks", p, c, cone[c], rootsRanks[p][c], roots[p][c], leavesRanks[p][c], leaves[p][c]); 826 PetscCheck(ranks[r] >= 0 && ranks[r] < size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "p=%" PetscInt_FMT " c=%" PetscInt_FMT " commsize=%d: ranks[%" PetscInt_FMT "] = %d makes no sense", p, c, size, r, ranks[r]); 827 /* Find point leaves[p][c] among remote points aimed at rank leavesRanks[p][c] */ 828 rS = roffset[r]; 829 rN = roffset[r + 1] - rS; 830 PetscCall(PetscFindInt(leaves[p][c], rN, &rremote1[rS], &ind0)); 831 PetscCheck(ind0 >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " cone[%" PetscInt_FMT "]=%" PetscInt_FMT " root (%d,%" PetscInt_FMT ") leave (%d,%" PetscInt_FMT "): corresponding remote point not found - it seems there is missing connection in point SF!", p, c, cone[c], rootsRanks[p][c], roots[p][c], leavesRanks[p][c], leaves[p][c]); 832 /* Get the corresponding local point */ 833 mainCone[c] = rmine1[rS + ind0]; 834 } 835 if (debug) PetscCall(PetscSynchronizedPrintf(comm, " mainCone=[%4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT "]\n", mainCone[0], mainCone[1], mainCone[2], mainCone[3])); 836 /* Set the desired order of p's cone points and fix orientations accordingly */ 837 PetscCall(DMPolytopeGetOrientation(ct, cone, mainCone, &o)); 838 PetscCall(DMPlexOrientPoint(dm, p, o)); 839 } else if (debug) PetscCall(PetscSynchronizedPrintf(comm, " ==\n")); 840 } 841 if (debug) { 842 PetscCall(PetscSynchronizedFlush(comm, NULL)); 843 PetscCallMPI(MPI_Barrier(comm)); 844 } 845 PetscCall(DMViewFromOptions(dm, NULL, "-after_orient_interface_dm_view")); 846 PetscCall(PetscFree4(roots, leaves, rootsRanks, leavesRanks)); 847 PetscCall(PetscFree2(rmine1, rremote1)); 848 PetscFunctionReturn(0); 849 } 850 851 static PetscErrorCode IntArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], const char valname[], PetscInt n, const PetscInt a[]) { 852 PetscInt idx; 853 PetscMPIInt rank; 854 PetscBool flg; 855 856 PetscFunctionBegin; 857 PetscCall(PetscOptionsHasName(NULL, NULL, opt, &flg)); 858 if (!flg) PetscFunctionReturn(0); 859 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 860 PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name)); 861 for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s %" PetscInt_FMT " %s %" PetscInt_FMT "\n", rank, idxname, idx, valname, a[idx])); 862 PetscCall(PetscSynchronizedFlush(comm, NULL)); 863 PetscFunctionReturn(0); 864 } 865 866 static PetscErrorCode SFNodeArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], PetscInt n, const PetscSFNode a[]) { 867 PetscInt idx; 868 PetscMPIInt rank; 869 PetscBool flg; 870 871 PetscFunctionBegin; 872 PetscCall(PetscOptionsHasName(NULL, NULL, opt, &flg)); 873 if (!flg) PetscFunctionReturn(0); 874 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 875 PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name)); 876 if (idxname) { 877 for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s %" PetscInt_FMT " rank %" PetscInt_FMT " index %" PetscInt_FMT "\n", rank, idxname, idx, a[idx].rank, a[idx].index)); 878 } else { 879 for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]rank %" PetscInt_FMT " index %" PetscInt_FMT "\n", rank, a[idx].rank, a[idx].index)); 880 } 881 PetscCall(PetscSynchronizedFlush(comm, NULL)); 882 PetscFunctionReturn(0); 883 } 884 885 static PetscErrorCode DMPlexMapToLocalPoint(DM dm, PetscHMapIJ remotehash, PetscSFNode remotePoint, PetscInt *localPoint, PetscBool *mapFailed) { 886 PetscSF sf; 887 const PetscInt *locals; 888 PetscMPIInt rank; 889 890 PetscFunctionBegin; 891 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 892 PetscCall(DMGetPointSF(dm, &sf)); 893 PetscCall(PetscSFGetGraph(sf, NULL, NULL, &locals, NULL)); 894 if (mapFailed) *mapFailed = PETSC_FALSE; 895 if (remotePoint.rank == rank) { 896 *localPoint = remotePoint.index; 897 } else { 898 PetscHashIJKey key; 899 PetscInt l; 900 901 key.i = remotePoint.index; 902 key.j = remotePoint.rank; 903 PetscCall(PetscHMapIJGet(remotehash, key, &l)); 904 if (l >= 0) { 905 *localPoint = locals[l]; 906 } else if (mapFailed) *mapFailed = PETSC_TRUE; 907 } 908 PetscFunctionReturn(0); 909 } 910 911 static PetscErrorCode DMPlexMapToGlobalPoint(DM dm, PetscInt localPoint, PetscSFNode *remotePoint, PetscBool *mapFailed) { 912 PetscSF sf; 913 const PetscInt *locals, *rootdegree; 914 const PetscSFNode *remotes; 915 PetscInt Nl, l; 916 PetscMPIInt rank; 917 918 PetscFunctionBegin; 919 if (mapFailed) *mapFailed = PETSC_FALSE; 920 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 921 PetscCall(DMGetPointSF(dm, &sf)); 922 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &locals, &remotes)); 923 if (Nl < 0) goto owned; 924 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 925 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 926 if (rootdegree[localPoint]) goto owned; 927 PetscCall(PetscFindInt(localPoint, Nl, locals, &l)); 928 if (l < 0) { 929 if (mapFailed) *mapFailed = PETSC_TRUE; 930 } else *remotePoint = remotes[l]; 931 PetscFunctionReturn(0); 932 owned: 933 remotePoint->rank = rank; 934 remotePoint->index = localPoint; 935 PetscFunctionReturn(0); 936 } 937 938 static PetscErrorCode DMPlexPointIsShared(DM dm, PetscInt p, PetscBool *isShared) { 939 PetscSF sf; 940 const PetscInt *locals, *rootdegree; 941 PetscInt Nl, idx; 942 943 PetscFunctionBegin; 944 *isShared = PETSC_FALSE; 945 PetscCall(DMGetPointSF(dm, &sf)); 946 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &locals, NULL)); 947 if (Nl < 0) PetscFunctionReturn(0); 948 PetscCall(PetscFindInt(p, Nl, locals, &idx)); 949 if (idx >= 0) { 950 *isShared = PETSC_TRUE; 951 PetscFunctionReturn(0); 952 } 953 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 954 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 955 if (rootdegree[p] > 0) *isShared = PETSC_TRUE; 956 PetscFunctionReturn(0); 957 } 958 959 static PetscErrorCode DMPlexConeIsShared(DM dm, PetscInt p, PetscBool *isShared) { 960 const PetscInt *cone; 961 PetscInt coneSize, c; 962 PetscBool cShared = PETSC_TRUE; 963 964 PetscFunctionBegin; 965 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 966 PetscCall(DMPlexGetCone(dm, p, &cone)); 967 for (c = 0; c < coneSize; ++c) { 968 PetscBool pointShared; 969 970 PetscCall(DMPlexPointIsShared(dm, cone[c], &pointShared)); 971 cShared = (PetscBool)(cShared && pointShared); 972 } 973 *isShared = coneSize ? cShared : PETSC_FALSE; 974 PetscFunctionReturn(0); 975 } 976 977 static PetscErrorCode DMPlexGetConeMinimum(DM dm, PetscInt p, PetscSFNode *cpmin) { 978 const PetscInt *cone; 979 PetscInt coneSize, c; 980 PetscSFNode cmin = {PETSC_MAX_INT, PETSC_MAX_INT}, missing = {-1, -1}; 981 982 PetscFunctionBegin; 983 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 984 PetscCall(DMPlexGetCone(dm, p, &cone)); 985 for (c = 0; c < coneSize; ++c) { 986 PetscSFNode rcp; 987 PetscBool mapFailed; 988 989 PetscCall(DMPlexMapToGlobalPoint(dm, cone[c], &rcp, &mapFailed)); 990 if (mapFailed) { 991 cmin = missing; 992 } else { 993 cmin = (rcp.rank < cmin.rank) || (rcp.rank == cmin.rank && rcp.index < cmin.index) ? rcp : cmin; 994 } 995 } 996 *cpmin = coneSize ? cmin : missing; 997 PetscFunctionReturn(0); 998 } 999 1000 /* 1001 Each shared face has an entry in the candidates array: 1002 (-1, coneSize-1), {(global cone point)} 1003 where the set is missing the point p which we use as the key for the face 1004 */ 1005 static PetscErrorCode DMPlexAddSharedFace_Private(DM dm, PetscSection candidateSection, PetscSFNode candidates[], PetscHMapIJ faceHash, PetscInt p, PetscBool debug) { 1006 MPI_Comm comm; 1007 const PetscInt *support; 1008 PetscInt supportSize, s, off = 0, idx = 0, overlap, cellHeight, height; 1009 PetscMPIInt rank; 1010 1011 PetscFunctionBegin; 1012 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1013 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1014 PetscCall(DMPlexGetOverlap(dm, &overlap)); 1015 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1016 PetscCall(DMPlexGetPointHeight(dm, p, &height)); 1017 if (!overlap && height <= cellHeight + 1) { 1018 /* cells can't be shared for non-overlapping meshes */ 1019 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Skipping face %" PetscInt_FMT " to avoid adding cell to hashmap since this is nonoverlapping mesh\n", rank, p)); 1020 PetscFunctionReturn(0); 1021 } 1022 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 1023 PetscCall(DMPlexGetSupport(dm, p, &support)); 1024 if (candidates) PetscCall(PetscSectionGetOffset(candidateSection, p, &off)); 1025 for (s = 0; s < supportSize; ++s) { 1026 const PetscInt face = support[s]; 1027 const PetscInt *cone; 1028 PetscSFNode cpmin = {-1, -1}, rp = {-1, -1}; 1029 PetscInt coneSize, c, f; 1030 PetscBool isShared = PETSC_FALSE; 1031 PetscHashIJKey key; 1032 1033 /* Only add point once */ 1034 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Support face %" PetscInt_FMT "\n", rank, face)); 1035 key.i = p; 1036 key.j = face; 1037 PetscCall(PetscHMapIJGet(faceHash, key, &f)); 1038 if (f >= 0) continue; 1039 PetscCall(DMPlexConeIsShared(dm, face, &isShared)); 1040 PetscCall(DMPlexGetConeMinimum(dm, face, &cpmin)); 1041 PetscCall(DMPlexMapToGlobalPoint(dm, p, &rp, NULL)); 1042 if (debug) { 1043 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Face point %" PetscInt_FMT " is shared: %d\n", rank, face, (int)isShared)); 1044 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Global point (%" PetscInt_FMT ", %" PetscInt_FMT ") Min Cone Point (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rp.rank, rp.index, cpmin.rank, cpmin.index)); 1045 } 1046 if (isShared && (rp.rank == cpmin.rank && rp.index == cpmin.index)) { 1047 PetscCall(PetscHMapIJSet(faceHash, key, p)); 1048 if (candidates) { 1049 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Adding shared face %" PetscInt_FMT " at idx %" PetscInt_FMT "\n[%d] ", rank, face, idx, rank)); 1050 PetscCall(DMPlexGetConeSize(dm, face, &coneSize)); 1051 PetscCall(DMPlexGetCone(dm, face, &cone)); 1052 candidates[off + idx].rank = -1; 1053 candidates[off + idx++].index = coneSize - 1; 1054 candidates[off + idx].rank = rank; 1055 candidates[off + idx++].index = face; 1056 for (c = 0; c < coneSize; ++c) { 1057 const PetscInt cp = cone[c]; 1058 1059 if (cp == p) continue; 1060 PetscCall(DMPlexMapToGlobalPoint(dm, cp, &candidates[off + idx], NULL)); 1061 if (debug) PetscCall(PetscSynchronizedPrintf(comm, " (%" PetscInt_FMT ",%" PetscInt_FMT ")", candidates[off + idx].rank, candidates[off + idx].index)); 1062 ++idx; 1063 } 1064 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "\n")); 1065 } else { 1066 /* Add cone size to section */ 1067 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Scheduling shared face %" PetscInt_FMT "\n", rank, face)); 1068 PetscCall(DMPlexGetConeSize(dm, face, &coneSize)); 1069 PetscCall(PetscHMapIJSet(faceHash, key, p)); 1070 PetscCall(PetscSectionAddDof(candidateSection, p, coneSize + 1)); 1071 } 1072 } 1073 } 1074 PetscFunctionReturn(0); 1075 } 1076 1077 /*@ 1078 DMPlexInterpolatePointSF - Insert interpolated points in the overlap into the PointSF in parallel, following local interpolation 1079 1080 Collective on dm 1081 1082 Input Parameters: 1083 + dm - The interpolated DM 1084 - pointSF - The initial SF without interpolated points 1085 1086 Output Parameter: 1087 . pointSF - The SF including interpolated points 1088 1089 Level: developer 1090 1091 Note: All debugging for this process can be turned on with the options: -dm_interp_pre_view -petscsf_interp_pre_view -petscsection_interp_candidate_view -petscsection_interp_candidate_remote_view -petscsection_interp_claim_view -petscsf_interp_pre_view -dmplex_interp_debug 1092 1093 .seealso: `DMPlexInterpolate()`, `DMPlexUninterpolate()` 1094 @*/ 1095 PetscErrorCode DMPlexInterpolatePointSF(DM dm, PetscSF pointSF) { 1096 MPI_Comm comm; 1097 PetscHMapIJ remoteHash; 1098 PetscHMapI claimshash; 1099 PetscSection candidateSection, candidateRemoteSection, claimSection; 1100 PetscSFNode *candidates, *candidatesRemote, *claims; 1101 const PetscInt *localPoints, *rootdegree; 1102 const PetscSFNode *remotePoints; 1103 PetscInt ov, Nr, r, Nl, l; 1104 PetscInt candidatesSize, candidatesRemoteSize, claimsSize; 1105 PetscBool flg, debug = PETSC_FALSE; 1106 PetscMPIInt rank; 1107 1108 PetscFunctionBegin; 1109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1110 PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 1111 PetscCall(DMPlexIsDistributed(dm, &flg)); 1112 if (!flg) PetscFunctionReturn(0); 1113 /* Set initial SF so that lower level queries work */ 1114 PetscCall(DMSetPointSF(dm, pointSF)); 1115 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1116 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1117 PetscCall(DMPlexGetOverlap(dm, &ov)); 1118 PetscCheck(!ov, comm, PETSC_ERR_SUP, "Interpolation of overlapped DMPlex not implemented yet"); 1119 PetscCall(PetscOptionsHasName(NULL, ((PetscObject)dm)->prefix, "-dmplex_interp_debug", &debug)); 1120 PetscCall(PetscObjectViewFromOptions((PetscObject)dm, NULL, "-dm_interp_pre_view")); 1121 PetscCall(PetscObjectViewFromOptions((PetscObject)pointSF, NULL, "-petscsf_interp_pre_view")); 1122 PetscCall(PetscLogEventBegin(DMPLEX_InterpolateSF, dm, 0, 0, 0)); 1123 /* Step 0: Precalculations */ 1124 PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &localPoints, &remotePoints)); 1125 PetscCheck(Nr >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but input PointSF has no graph set"); 1126 PetscCall(PetscHMapIJCreate(&remoteHash)); 1127 for (l = 0; l < Nl; ++l) { 1128 PetscHashIJKey key; 1129 key.i = remotePoints[l].index; 1130 key.j = remotePoints[l].rank; 1131 PetscCall(PetscHMapIJSet(remoteHash, key, l)); 1132 } 1133 /* Compute root degree to identify shared points */ 1134 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 1135 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 1136 PetscCall(IntArrayViewFromOptions(comm, "-interp_root_degree_view", "Root degree", "point", "degree", Nr, rootdegree)); 1137 /* 1138 1) Loop over each leaf point $p$ at depth $d$ in the SF 1139 \item Get set $F(p)$ of faces $f$ in the support of $p$ for which 1140 \begin{itemize} 1141 \item all cone points of $f$ are shared 1142 \item $p$ is the cone point with smallest canonical number 1143 \end{itemize} 1144 \item Send $F(p)$ and the cone of each face to the active root point $r(p)$ 1145 \item At the root, if at least two faces with a given cone are present, including a local face, mark the face as shared \label{alg:rootStep} and choose the root face 1146 \item Send the root face from the root back to all leaf process 1147 \item Leaf processes add the shared face to the SF 1148 */ 1149 /* Step 1: Construct section+SFNode array 1150 The section has entries for all shared faces for which we have a leaf point in the cone 1151 The array holds candidate shared faces, each face is refered to by the leaf point */ 1152 PetscCall(PetscSectionCreate(comm, &candidateSection)); 1153 PetscCall(PetscSectionSetChart(candidateSection, 0, Nr)); 1154 { 1155 PetscHMapIJ faceHash; 1156 1157 PetscCall(PetscHMapIJCreate(&faceHash)); 1158 for (l = 0; l < Nl; ++l) { 1159 const PetscInt p = localPoints[l]; 1160 1161 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] First pass leaf point %" PetscInt_FMT "\n", rank, p)); 1162 PetscCall(DMPlexAddSharedFace_Private(dm, candidateSection, NULL, faceHash, p, debug)); 1163 } 1164 PetscCall(PetscHMapIJClear(faceHash)); 1165 PetscCall(PetscSectionSetUp(candidateSection)); 1166 PetscCall(PetscSectionGetStorageSize(candidateSection, &candidatesSize)); 1167 PetscCall(PetscMalloc1(candidatesSize, &candidates)); 1168 for (l = 0; l < Nl; ++l) { 1169 const PetscInt p = localPoints[l]; 1170 1171 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Second pass leaf point %" PetscInt_FMT "\n", rank, p)); 1172 PetscCall(DMPlexAddSharedFace_Private(dm, candidateSection, candidates, faceHash, p, debug)); 1173 } 1174 PetscCall(PetscHMapIJDestroy(&faceHash)); 1175 if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 1176 } 1177 PetscCall(PetscObjectSetName((PetscObject)candidateSection, "Candidate Section")); 1178 PetscCall(PetscObjectViewFromOptions((PetscObject)candidateSection, NULL, "-petscsection_interp_candidate_view")); 1179 PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_view", "Candidates", NULL, candidatesSize, candidates)); 1180 /* Step 2: Gather candidate section / array pair into the root partition via inverse(multi(pointSF)). */ 1181 /* Note that this section is indexed by offsets into leaves, not by point number */ 1182 { 1183 PetscSF sfMulti, sfInverse, sfCandidates; 1184 PetscInt *remoteOffsets; 1185 1186 PetscCall(PetscSFGetMultiSF(pointSF, &sfMulti)); 1187 PetscCall(PetscSFCreateInverseSF(sfMulti, &sfInverse)); 1188 PetscCall(PetscSectionCreate(comm, &candidateRemoteSection)); 1189 PetscCall(PetscSFDistributeSection(sfInverse, candidateSection, &remoteOffsets, candidateRemoteSection)); 1190 PetscCall(PetscSFCreateSectionSF(sfInverse, candidateSection, remoteOffsets, candidateRemoteSection, &sfCandidates)); 1191 PetscCall(PetscSectionGetStorageSize(candidateRemoteSection, &candidatesRemoteSize)); 1192 PetscCall(PetscMalloc1(candidatesRemoteSize, &candidatesRemote)); 1193 PetscCall(PetscSFBcastBegin(sfCandidates, MPIU_2INT, candidates, candidatesRemote, MPI_REPLACE)); 1194 PetscCall(PetscSFBcastEnd(sfCandidates, MPIU_2INT, candidates, candidatesRemote, MPI_REPLACE)); 1195 PetscCall(PetscSFDestroy(&sfInverse)); 1196 PetscCall(PetscSFDestroy(&sfCandidates)); 1197 PetscCall(PetscFree(remoteOffsets)); 1198 1199 PetscCall(PetscObjectSetName((PetscObject)candidateRemoteSection, "Remote Candidate Section")); 1200 PetscCall(PetscObjectViewFromOptions((PetscObject)candidateRemoteSection, NULL, "-petscsection_interp_candidate_remote_view")); 1201 PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_remote_view", "Remote Candidates", NULL, candidatesRemoteSize, candidatesRemote)); 1202 } 1203 /* Step 3: At the root, if at least two faces with a given cone are present, including a local face, mark the face as shared and choose the root face */ 1204 { 1205 PetscHashIJKLRemote faceTable; 1206 PetscInt idx, idx2; 1207 1208 PetscCall(PetscHashIJKLRemoteCreate(&faceTable)); 1209 /* There is a section point for every leaf attached to a given root point */ 1210 for (r = 0, idx = 0, idx2 = 0; r < Nr; ++r) { 1211 PetscInt deg; 1212 1213 for (deg = 0; deg < rootdegree[r]; ++deg, ++idx) { 1214 PetscInt offset, dof, d; 1215 1216 PetscCall(PetscSectionGetDof(candidateRemoteSection, idx, &dof)); 1217 PetscCall(PetscSectionGetOffset(candidateRemoteSection, idx, &offset)); 1218 /* dof may include many faces from the remote process */ 1219 for (d = 0; d < dof; ++d) { 1220 const PetscInt hidx = offset + d; 1221 const PetscInt Np = candidatesRemote[hidx].index + 1; 1222 const PetscSFNode rface = candidatesRemote[hidx + 1]; 1223 const PetscSFNode *fcone = &candidatesRemote[hidx + 2]; 1224 PetscSFNode fcp0; 1225 const PetscSFNode pmax = {PETSC_MAX_INT, PETSC_MAX_INT}; 1226 const PetscInt *join = NULL; 1227 PetscHashIJKLRemoteKey key; 1228 PetscHashIter iter; 1229 PetscBool missing, mapToLocalPointFailed = PETSC_FALSE; 1230 PetscInt points[1024], p, joinSize; 1231 1232 if (debug) 1233 PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Checking face (%" PetscInt_FMT ", %" PetscInt_FMT ") at (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") with cone size %" PetscInt_FMT "\n", rank, rface.rank, 1234 rface.index, r, idx, d, Np)); 1235 PetscCheck(Np <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle face (%" PetscInt_FMT ", %" PetscInt_FMT ") at (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") with %" PetscInt_FMT " cone points", rface.rank, rface.index, r, idx, d, Np); 1236 fcp0.rank = rank; 1237 fcp0.index = r; 1238 d += Np; 1239 /* Put remote face in hash table */ 1240 key.i = fcp0; 1241 key.j = fcone[0]; 1242 key.k = Np > 2 ? fcone[1] : pmax; 1243 key.l = Np > 3 ? fcone[2] : pmax; 1244 PetscCall(PetscSortSFNode(Np, (PetscSFNode *)&key)); 1245 PetscCall(PetscHashIJKLRemotePut(faceTable, key, &iter, &missing)); 1246 if (missing) { 1247 if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Setting remote face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rface.index, rface.rank)); 1248 PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, rface)); 1249 } else { 1250 PetscSFNode oface; 1251 1252 PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &oface)); 1253 if ((rface.rank < oface.rank) || (rface.rank == oface.rank && rface.index < oface.index)) { 1254 if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Replacing with remote face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rface.index, rface.rank)); 1255 PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, rface)); 1256 } 1257 } 1258 /* Check for local face */ 1259 points[0] = r; 1260 for (p = 1; p < Np; ++p) { 1261 PetscCall(DMPlexMapToLocalPoint(dm, remoteHash, fcone[p - 1], &points[p], &mapToLocalPointFailed)); 1262 if (mapToLocalPointFailed) break; /* We got a point not in our overlap */ 1263 if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Checking local candidate %" PetscInt_FMT "\n", rank, points[p])); 1264 } 1265 if (mapToLocalPointFailed) continue; 1266 PetscCall(DMPlexGetJoin(dm, Np, points, &joinSize, &join)); 1267 if (joinSize == 1) { 1268 PetscSFNode lface; 1269 PetscSFNode oface; 1270 1271 /* Always replace with local face */ 1272 lface.rank = rank; 1273 lface.index = join[0]; 1274 PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &oface)); 1275 if (debug) 1276 PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Replacing (%" PetscInt_FMT ", %" PetscInt_FMT ") with local face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, oface.index, oface.rank, lface.index, lface.rank)); 1277 PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, lface)); 1278 } 1279 PetscCall(DMPlexRestoreJoin(dm, Np, points, &joinSize, &join)); 1280 } 1281 } 1282 /* Put back faces for this root */ 1283 for (deg = 0; deg < rootdegree[r]; ++deg, ++idx2) { 1284 PetscInt offset, dof, d; 1285 1286 PetscCall(PetscSectionGetDof(candidateRemoteSection, idx2, &dof)); 1287 PetscCall(PetscSectionGetOffset(candidateRemoteSection, idx2, &offset)); 1288 /* dof may include many faces from the remote process */ 1289 for (d = 0; d < dof; ++d) { 1290 const PetscInt hidx = offset + d; 1291 const PetscInt Np = candidatesRemote[hidx].index + 1; 1292 const PetscSFNode *fcone = &candidatesRemote[hidx + 2]; 1293 PetscSFNode fcp0; 1294 const PetscSFNode pmax = {PETSC_MAX_INT, PETSC_MAX_INT}; 1295 PetscHashIJKLRemoteKey key; 1296 PetscHashIter iter; 1297 PetscBool missing; 1298 1299 if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Entering face at (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, r, idx)); 1300 PetscCheck(Np <= 4, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle faces with %" PetscInt_FMT " cone points", Np); 1301 fcp0.rank = rank; 1302 fcp0.index = r; 1303 d += Np; 1304 /* Find remote face in hash table */ 1305 key.i = fcp0; 1306 key.j = fcone[0]; 1307 key.k = Np > 2 ? fcone[1] : pmax; 1308 key.l = Np > 3 ? fcone[2] : pmax; 1309 PetscCall(PetscSortSFNode(Np, (PetscSFNode *)&key)); 1310 if (debug) 1311 PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] key (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, 1312 key.i.rank, key.i.index, key.j.rank, key.j.index, key.k.rank, key.k.index, key.l.rank, key.l.index)); 1313 PetscCall(PetscHashIJKLRemotePut(faceTable, key, &iter, &missing)); 1314 PetscCheck(!missing, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Root %" PetscInt_FMT " Idx %" PetscInt_FMT " ought to have an associated face", r, idx2); 1315 PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &candidatesRemote[hidx])); 1316 } 1317 } 1318 } 1319 if (debug) PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)dm), NULL)); 1320 PetscCall(PetscHashIJKLRemoteDestroy(&faceTable)); 1321 } 1322 /* Step 4: Push back owned faces */ 1323 { 1324 PetscSF sfMulti, sfClaims, sfPointNew; 1325 PetscSFNode *remotePointsNew; 1326 PetscInt *remoteOffsets, *localPointsNew; 1327 PetscInt pStart, pEnd, r, NlNew, p; 1328 1329 /* 4) Push claims back to receiver via the MultiSF and derive new pointSF mapping on receiver */ 1330 PetscCall(PetscSFGetMultiSF(pointSF, &sfMulti)); 1331 PetscCall(PetscSectionCreate(comm, &claimSection)); 1332 PetscCall(PetscSFDistributeSection(sfMulti, candidateRemoteSection, &remoteOffsets, claimSection)); 1333 PetscCall(PetscSFCreateSectionSF(sfMulti, candidateRemoteSection, remoteOffsets, claimSection, &sfClaims)); 1334 PetscCall(PetscSectionGetStorageSize(claimSection, &claimsSize)); 1335 PetscCall(PetscMalloc1(claimsSize, &claims)); 1336 for (p = 0; p < claimsSize; ++p) claims[p].rank = -1; 1337 PetscCall(PetscSFBcastBegin(sfClaims, MPIU_2INT, candidatesRemote, claims, MPI_REPLACE)); 1338 PetscCall(PetscSFBcastEnd(sfClaims, MPIU_2INT, candidatesRemote, claims, MPI_REPLACE)); 1339 PetscCall(PetscSFDestroy(&sfClaims)); 1340 PetscCall(PetscFree(remoteOffsets)); 1341 PetscCall(PetscObjectSetName((PetscObject)claimSection, "Claim Section")); 1342 PetscCall(PetscObjectViewFromOptions((PetscObject)claimSection, NULL, "-petscsection_interp_claim_view")); 1343 PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_claim_view", "Claims", NULL, claimsSize, claims)); 1344 /* Step 5) Walk the original section of local supports and add an SF entry for each updated item */ 1345 /* TODO I should not have to do a join here since I already put the face and its cone in the candidate section */ 1346 PetscCall(PetscHMapICreate(&claimshash)); 1347 for (r = 0; r < Nr; ++r) { 1348 PetscInt dof, off, d; 1349 1350 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Checking root for claims %" PetscInt_FMT "\n", rank, r)); 1351 PetscCall(PetscSectionGetDof(candidateSection, r, &dof)); 1352 PetscCall(PetscSectionGetOffset(candidateSection, r, &off)); 1353 for (d = 0; d < dof;) { 1354 if (claims[off + d].rank >= 0) { 1355 const PetscInt faceInd = off + d; 1356 const PetscInt Np = candidates[off + d].index; 1357 const PetscInt *join = NULL; 1358 PetscInt joinSize, points[1024], c; 1359 1360 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Found claim for remote point (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, claims[faceInd].rank, claims[faceInd].index)); 1361 points[0] = r; 1362 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] point %" PetscInt_FMT "\n", rank, points[0])); 1363 for (c = 0, d += 2; c < Np; ++c, ++d) { 1364 PetscCall(DMPlexMapToLocalPoint(dm, remoteHash, candidates[off + d], &points[c + 1], NULL)); 1365 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] point %" PetscInt_FMT "\n", rank, points[c + 1])); 1366 } 1367 PetscCall(DMPlexGetJoin(dm, Np + 1, points, &joinSize, &join)); 1368 if (joinSize == 1) { 1369 if (claims[faceInd].rank == rank) { 1370 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Ignoring local face %" PetscInt_FMT " for non-remote partner\n", rank, join[0])); 1371 } else { 1372 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Found local face %" PetscInt_FMT "\n", rank, join[0])); 1373 PetscCall(PetscHMapISet(claimshash, join[0], faceInd)); 1374 } 1375 } else { 1376 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Failed to find face\n", rank)); 1377 } 1378 PetscCall(DMPlexRestoreJoin(dm, Np + 1, points, &joinSize, &join)); 1379 } else { 1380 if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] No claim for point %" PetscInt_FMT "\n", rank, r)); 1381 d += claims[off + d].index + 1; 1382 } 1383 } 1384 } 1385 if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 1386 /* Step 6) Create new pointSF from hashed claims */ 1387 PetscCall(PetscHMapIGetSize(claimshash, &NlNew)); 1388 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1389 PetscCall(PetscMalloc1(Nl + NlNew, &localPointsNew)); 1390 PetscCall(PetscMalloc1(Nl + NlNew, &remotePointsNew)); 1391 for (l = 0; l < Nl; ++l) { 1392 localPointsNew[l] = localPoints[l]; 1393 remotePointsNew[l].index = remotePoints[l].index; 1394 remotePointsNew[l].rank = remotePoints[l].rank; 1395 } 1396 p = Nl; 1397 PetscCall(PetscHMapIGetKeys(claimshash, &p, localPointsNew)); 1398 /* We sort new points, and assume they are numbered after all existing points */ 1399 PetscCall(PetscSortInt(NlNew, &localPointsNew[Nl])); 1400 for (p = Nl; p < Nl + NlNew; ++p) { 1401 PetscInt off; 1402 PetscCall(PetscHMapIGet(claimshash, localPointsNew[p], &off)); 1403 PetscCheck(claims[off].rank >= 0 && claims[off].index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid claim for local point %" PetscInt_FMT ", (%" PetscInt_FMT ", %" PetscInt_FMT ")", localPointsNew[p], claims[off].rank, claims[off].index); 1404 remotePointsNew[p] = claims[off]; 1405 } 1406 PetscCall(PetscSFCreate(comm, &sfPointNew)); 1407 PetscCall(PetscSFSetGraph(sfPointNew, pEnd - pStart, Nl + NlNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER)); 1408 PetscCall(PetscSFSetUp(sfPointNew)); 1409 PetscCall(DMSetPointSF(dm, sfPointNew)); 1410 PetscCall(PetscObjectViewFromOptions((PetscObject)sfPointNew, NULL, "-petscsf_interp_view")); 1411 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sfPointNew)); 1412 PetscCall(PetscSFDestroy(&sfPointNew)); 1413 PetscCall(PetscHMapIDestroy(&claimshash)); 1414 } 1415 PetscCall(PetscHMapIJDestroy(&remoteHash)); 1416 PetscCall(PetscSectionDestroy(&candidateSection)); 1417 PetscCall(PetscSectionDestroy(&candidateRemoteSection)); 1418 PetscCall(PetscSectionDestroy(&claimSection)); 1419 PetscCall(PetscFree(candidates)); 1420 PetscCall(PetscFree(candidatesRemote)); 1421 PetscCall(PetscFree(claims)); 1422 PetscCall(PetscLogEventEnd(DMPLEX_InterpolateSF, dm, 0, 0, 0)); 1423 PetscFunctionReturn(0); 1424 } 1425 1426 /*@ 1427 DMPlexInterpolate - Take in a cell-vertex mesh and return one with all intermediate faces, edges, etc. 1428 1429 Collective on dm 1430 1431 Input Parameters: 1432 + dm - The DMPlex object with only cells and vertices 1433 - dmInt - The interpolated DM 1434 1435 Output Parameter: 1436 . dmInt - The complete DMPlex object 1437 1438 Level: intermediate 1439 1440 Notes: 1441 Labels and coordinates are copied. 1442 1443 Developer Notes: 1444 It sets plex->interpolated = DMPLEX_INTERPOLATED_FULL. 1445 1446 .seealso: `DMPlexUninterpolate()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCopyCoordinates()` 1447 @*/ 1448 PetscErrorCode DMPlexInterpolate(DM dm, DM *dmInt) { 1449 DMPlexInterpolatedFlag interpolated; 1450 DM idm, odm = dm; 1451 PetscSF sfPoint; 1452 PetscInt depth, dim, d; 1453 const char *name; 1454 PetscBool flg = PETSC_TRUE; 1455 1456 PetscFunctionBegin; 1457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1458 PetscValidPointer(dmInt, 2); 1459 PetscCall(PetscLogEventBegin(DMPLEX_Interpolate, dm, 0, 0, 0)); 1460 PetscCall(DMPlexGetDepth(dm, &depth)); 1461 PetscCall(DMGetDimension(dm, &dim)); 1462 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 1463 PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 1464 if (interpolated == DMPLEX_INTERPOLATED_FULL) { 1465 PetscCall(PetscObjectReference((PetscObject)dm)); 1466 idm = dm; 1467 } else { 1468 for (d = 1; d < dim; ++d) { 1469 /* Create interpolated mesh */ 1470 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &idm)); 1471 PetscCall(DMSetType(idm, DMPLEX)); 1472 PetscCall(DMSetDimension(idm, dim)); 1473 if (depth > 0) { 1474 PetscCall(DMPlexInterpolateFaces_Internal(odm, 1, idm)); 1475 PetscCall(DMGetPointSF(odm, &sfPoint)); 1476 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(odm, sfPoint)); 1477 { 1478 /* TODO: We need to systematically fix cases of distributed Plexes with no graph set */ 1479 PetscInt nroots; 1480 PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL)); 1481 if (nroots >= 0) PetscCall(DMPlexInterpolatePointSF(idm, sfPoint)); 1482 } 1483 } 1484 if (odm != dm) PetscCall(DMDestroy(&odm)); 1485 odm = idm; 1486 } 1487 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1488 PetscCall(PetscObjectSetName((PetscObject)idm, name)); 1489 PetscCall(DMPlexCopyCoordinates(dm, idm)); 1490 PetscCall(DMCopyLabels(dm, idm, PETSC_COPY_VALUES, PETSC_FALSE, DM_COPY_LABELS_FAIL)); 1491 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_interpolate_orient_interfaces", &flg, NULL)); 1492 if (flg) PetscCall(DMPlexOrientInterface_Internal(idm)); 1493 } 1494 /* This function makes the mesh fully interpolated on all ranks */ 1495 { 1496 DM_Plex *plex = (DM_Plex *)idm->data; 1497 plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_FULL; 1498 } 1499 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, idm)); 1500 *dmInt = idm; 1501 PetscCall(PetscLogEventEnd(DMPLEX_Interpolate, dm, 0, 0, 0)); 1502 PetscFunctionReturn(0); 1503 } 1504 1505 /*@ 1506 DMPlexCopyCoordinates - Copy coordinates from one mesh to another with the same vertices 1507 1508 Collective on dmA 1509 1510 Input Parameter: 1511 . dmA - The DMPlex object with initial coordinates 1512 1513 Output Parameter: 1514 . dmB - The DMPlex object with copied coordinates 1515 1516 Level: intermediate 1517 1518 Note: This is typically used when adding pieces other than vertices to a mesh 1519 1520 .seealso: `DMCopyLabels()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMGetCoordinateSection()` 1521 @*/ 1522 PetscErrorCode DMPlexCopyCoordinates(DM dmA, DM dmB) { 1523 Vec coordinatesA, coordinatesB; 1524 VecType vtype; 1525 PetscSection coordSectionA, coordSectionB; 1526 PetscScalar *coordsA, *coordsB; 1527 PetscInt spaceDim, Nf, vStartA, vStartB, vEndA, vEndB, coordSizeB, v, d; 1528 PetscInt cStartA, cEndA, cStartB, cEndB, cS, cE, cdim; 1529 PetscBool lc = PETSC_FALSE; 1530 1531 PetscFunctionBegin; 1532 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 1533 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 1534 if (dmA == dmB) PetscFunctionReturn(0); 1535 PetscCall(DMGetCoordinateDim(dmA, &cdim)); 1536 PetscCall(DMSetCoordinateDim(dmB, cdim)); 1537 PetscCall(DMPlexGetDepthStratum(dmA, 0, &vStartA, &vEndA)); 1538 PetscCall(DMPlexGetDepthStratum(dmB, 0, &vStartB, &vEndB)); 1539 PetscCheck((vEndA - vStartA) == (vEndB - vStartB), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of vertices in first DM %" PetscInt_FMT " != %" PetscInt_FMT " in the second DM", vEndA - vStartA, vEndB - vStartB); 1540 /* Copy over discretization if it exists */ 1541 { 1542 DM cdmA, cdmB; 1543 PetscDS dsA, dsB; 1544 PetscObject objA, objB; 1545 PetscClassId idA, idB; 1546 const PetscScalar *constants; 1547 PetscInt cdim, Nc; 1548 1549 PetscCall(DMGetCoordinateDM(dmA, &cdmA)); 1550 PetscCall(DMGetCoordinateDM(dmB, &cdmB)); 1551 PetscCall(DMGetField(cdmA, 0, NULL, &objA)); 1552 PetscCall(DMGetField(cdmB, 0, NULL, &objB)); 1553 PetscCall(PetscObjectGetClassId(objA, &idA)); 1554 PetscCall(PetscObjectGetClassId(objB, &idB)); 1555 if ((idA == PETSCFE_CLASSID) && (idA != idB)) { 1556 PetscCall(DMSetField(cdmB, 0, NULL, objA)); 1557 PetscCall(DMCreateDS(cdmB)); 1558 PetscCall(DMGetDS(cdmA, &dsA)); 1559 PetscCall(DMGetDS(cdmB, &dsB)); 1560 PetscCall(PetscDSGetCoordinateDimension(dsA, &cdim)); 1561 PetscCall(PetscDSSetCoordinateDimension(dsB, cdim)); 1562 PetscCall(PetscDSGetConstants(dsA, &Nc, &constants)); 1563 PetscCall(PetscDSSetConstants(dsB, Nc, (PetscScalar *)constants)); 1564 } 1565 } 1566 PetscCall(DMPlexGetHeightStratum(dmA, 0, &cStartA, &cEndA)); 1567 PetscCall(DMPlexGetHeightStratum(dmB, 0, &cStartB, &cEndB)); 1568 PetscCall(DMGetCoordinateSection(dmA, &coordSectionA)); 1569 PetscCall(DMGetCoordinateSection(dmB, &coordSectionB)); 1570 if (coordSectionA == coordSectionB) PetscFunctionReturn(0); 1571 PetscCall(PetscSectionGetNumFields(coordSectionA, &Nf)); 1572 if (!Nf) PetscFunctionReturn(0); 1573 PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate fields must be 1, not %" PetscInt_FMT, Nf); 1574 if (!coordSectionB) { 1575 PetscInt dim; 1576 1577 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coordSectionA), &coordSectionB)); 1578 PetscCall(DMGetCoordinateDim(dmA, &dim)); 1579 PetscCall(DMSetCoordinateSection(dmB, dim, coordSectionB)); 1580 PetscCall(PetscObjectDereference((PetscObject)coordSectionB)); 1581 } 1582 PetscCall(PetscSectionSetNumFields(coordSectionB, 1)); 1583 PetscCall(PetscSectionGetFieldComponents(coordSectionA, 0, &spaceDim)); 1584 PetscCall(PetscSectionSetFieldComponents(coordSectionB, 0, spaceDim)); 1585 PetscCall(PetscSectionGetChart(coordSectionA, &cS, &cE)); 1586 if (cStartA <= cS && cS < cEndA) { /* localized coordinates */ 1587 PetscCheck((cEndA - cStartA) == (cEndB - cStartB), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cells in first DM %" PetscInt_FMT " != %" PetscInt_FMT " in the second DM", cEndA - cStartA, cEndB - cStartB); 1588 cS = cS - cStartA + cStartB; 1589 cE = vEndB; 1590 lc = PETSC_TRUE; 1591 } else { 1592 cS = vStartB; 1593 cE = vEndB; 1594 } 1595 PetscCall(PetscSectionSetChart(coordSectionB, cS, cE)); 1596 for (v = vStartB; v < vEndB; ++v) { 1597 PetscCall(PetscSectionSetDof(coordSectionB, v, spaceDim)); 1598 PetscCall(PetscSectionSetFieldDof(coordSectionB, v, 0, spaceDim)); 1599 } 1600 if (lc) { /* localized coordinates */ 1601 PetscInt c; 1602 1603 for (c = cS - cStartB; c < cEndB - cStartB; c++) { 1604 PetscInt dof; 1605 1606 PetscCall(PetscSectionGetDof(coordSectionA, c + cStartA, &dof)); 1607 PetscCall(PetscSectionSetDof(coordSectionB, c + cStartB, dof)); 1608 PetscCall(PetscSectionSetFieldDof(coordSectionB, c + cStartB, 0, dof)); 1609 } 1610 } 1611 PetscCall(PetscSectionSetUp(coordSectionB)); 1612 PetscCall(PetscSectionGetStorageSize(coordSectionB, &coordSizeB)); 1613 PetscCall(DMGetCoordinatesLocal(dmA, &coordinatesA)); 1614 PetscCall(VecCreate(PETSC_COMM_SELF, &coordinatesB)); 1615 PetscCall(PetscObjectSetName((PetscObject)coordinatesB, "coordinates")); 1616 PetscCall(VecSetSizes(coordinatesB, coordSizeB, PETSC_DETERMINE)); 1617 PetscCall(VecGetBlockSize(coordinatesA, &d)); 1618 PetscCall(VecSetBlockSize(coordinatesB, d)); 1619 PetscCall(VecGetType(coordinatesA, &vtype)); 1620 PetscCall(VecSetType(coordinatesB, vtype)); 1621 PetscCall(VecGetArray(coordinatesA, &coordsA)); 1622 PetscCall(VecGetArray(coordinatesB, &coordsB)); 1623 for (v = 0; v < vEndB - vStartB; ++v) { 1624 PetscInt offA, offB; 1625 1626 PetscCall(PetscSectionGetOffset(coordSectionA, v + vStartA, &offA)); 1627 PetscCall(PetscSectionGetOffset(coordSectionB, v + vStartB, &offB)); 1628 for (d = 0; d < spaceDim; ++d) coordsB[offB + d] = coordsA[offA + d]; 1629 } 1630 if (lc) { /* localized coordinates */ 1631 PetscInt c; 1632 1633 for (c = cS - cStartB; c < cEndB - cStartB; c++) { 1634 PetscInt dof, offA, offB; 1635 1636 PetscCall(PetscSectionGetOffset(coordSectionA, c + cStartA, &offA)); 1637 PetscCall(PetscSectionGetOffset(coordSectionB, c + cStartB, &offB)); 1638 PetscCall(PetscSectionGetDof(coordSectionA, c + cStartA, &dof)); 1639 PetscCall(PetscArraycpy(coordsB + offB, coordsA + offA, dof)); 1640 } 1641 } 1642 PetscCall(VecRestoreArray(coordinatesA, &coordsA)); 1643 PetscCall(VecRestoreArray(coordinatesB, &coordsB)); 1644 PetscCall(DMSetCoordinatesLocal(dmB, coordinatesB)); 1645 PetscCall(VecDestroy(&coordinatesB)); 1646 PetscFunctionReturn(0); 1647 } 1648 1649 /*@ 1650 DMPlexUninterpolate - Take in a mesh with all intermediate faces, edges, etc. and return a cell-vertex mesh 1651 1652 Collective on dm 1653 1654 Input Parameter: 1655 . dm - The complete DMPlex object 1656 1657 Output Parameter: 1658 . dmUnint - The DMPlex object with only cells and vertices 1659 1660 Level: intermediate 1661 1662 Notes: 1663 It does not copy over the coordinates. 1664 1665 Developer Notes: 1666 It sets plex->interpolated = DMPLEX_INTERPOLATED_NONE. 1667 1668 .seealso: `DMPlexInterpolate()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCopyCoordinates()` 1669 @*/ 1670 PetscErrorCode DMPlexUninterpolate(DM dm, DM *dmUnint) { 1671 DMPlexInterpolatedFlag interpolated; 1672 DM udm; 1673 PetscInt dim, vStart, vEnd, cStart, cEnd, c, maxConeSize = 0, *cone; 1674 1675 PetscFunctionBegin; 1676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1677 PetscValidPointer(dmUnint, 2); 1678 PetscCall(DMGetDimension(dm, &dim)); 1679 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 1680 PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 1681 if (interpolated == DMPLEX_INTERPOLATED_NONE || dim <= 1) { 1682 /* in case dim <= 1 just keep the DMPLEX_INTERPOLATED_FULL flag */ 1683 PetscCall(PetscObjectReference((PetscObject)dm)); 1684 *dmUnint = dm; 1685 PetscFunctionReturn(0); 1686 } 1687 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1688 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1689 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &udm)); 1690 PetscCall(DMSetType(udm, DMPLEX)); 1691 PetscCall(DMSetDimension(udm, dim)); 1692 PetscCall(DMPlexSetChart(udm, cStart, vEnd)); 1693 for (c = cStart; c < cEnd; ++c) { 1694 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 1695 1696 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1697 for (cl = 0; cl < closureSize * 2; cl += 2) { 1698 const PetscInt p = closure[cl]; 1699 1700 if ((p >= vStart) && (p < vEnd)) ++coneSize; 1701 } 1702 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1703 PetscCall(DMPlexSetConeSize(udm, c, coneSize)); 1704 maxConeSize = PetscMax(maxConeSize, coneSize); 1705 } 1706 PetscCall(DMSetUp(udm)); 1707 PetscCall(PetscMalloc1(maxConeSize, &cone)); 1708 for (c = cStart; c < cEnd; ++c) { 1709 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 1710 1711 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1712 for (cl = 0; cl < closureSize * 2; cl += 2) { 1713 const PetscInt p = closure[cl]; 1714 1715 if ((p >= vStart) && (p < vEnd)) cone[coneSize++] = p; 1716 } 1717 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1718 PetscCall(DMPlexSetCone(udm, c, cone)); 1719 } 1720 PetscCall(PetscFree(cone)); 1721 PetscCall(DMPlexSymmetrize(udm)); 1722 PetscCall(DMPlexStratify(udm)); 1723 /* Reduce SF */ 1724 { 1725 PetscSF sfPoint, sfPointUn; 1726 const PetscSFNode *remotePoints; 1727 const PetscInt *localPoints; 1728 PetscSFNode *remotePointsUn; 1729 PetscInt *localPointsUn; 1730 PetscInt numRoots, numLeaves, l; 1731 PetscInt numLeavesUn = 0, n = 0; 1732 1733 /* Get original SF information */ 1734 PetscCall(DMGetPointSF(dm, &sfPoint)); 1735 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sfPoint)); 1736 PetscCall(DMGetPointSF(udm, &sfPointUn)); 1737 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 1738 if (numRoots >= 0) { 1739 /* Allocate space for cells and vertices */ 1740 for (l = 0; l < numLeaves; ++l) { 1741 const PetscInt p = localPoints[l]; 1742 1743 if ((vStart <= p && p < vEnd) || (cStart <= p && p < cEnd)) numLeavesUn++; 1744 } 1745 /* Fill in leaves */ 1746 PetscCall(PetscMalloc1(numLeavesUn, &remotePointsUn)); 1747 PetscCall(PetscMalloc1(numLeavesUn, &localPointsUn)); 1748 for (l = 0; l < numLeaves; l++) { 1749 const PetscInt p = localPoints[l]; 1750 1751 if ((vStart <= p && p < vEnd) || (cStart <= p && p < cEnd)) { 1752 localPointsUn[n] = p; 1753 remotePointsUn[n].rank = remotePoints[l].rank; 1754 remotePointsUn[n].index = remotePoints[l].index; 1755 ++n; 1756 } 1757 } 1758 PetscCheck(n == numLeavesUn, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent number of leaves %" PetscInt_FMT " != %" PetscInt_FMT, n, numLeavesUn); 1759 PetscCall(PetscSFSetGraph(sfPointUn, cEnd - cStart + vEnd - vStart, numLeavesUn, localPointsUn, PETSC_OWN_POINTER, remotePointsUn, PETSC_OWN_POINTER)); 1760 } 1761 } 1762 /* This function makes the mesh fully uninterpolated on all ranks */ 1763 { 1764 DM_Plex *plex = (DM_Plex *)udm->data; 1765 plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_NONE; 1766 } 1767 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, udm)); 1768 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(udm, NULL)); 1769 *dmUnint = udm; 1770 PetscFunctionReturn(0); 1771 } 1772 1773 static PetscErrorCode DMPlexIsInterpolated_Internal(DM dm, DMPlexInterpolatedFlag *interpolated) { 1774 PetscInt coneSize, depth, dim, h, p, pStart, pEnd; 1775 MPI_Comm comm; 1776 1777 PetscFunctionBegin; 1778 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1779 PetscCall(DMPlexGetDepth(dm, &depth)); 1780 PetscCall(DMGetDimension(dm, &dim)); 1781 1782 if (depth == dim) { 1783 *interpolated = DMPLEX_INTERPOLATED_FULL; 1784 if (!dim) goto finish; 1785 1786 /* Check points at height = dim are vertices (have no cones) */ 1787 PetscCall(DMPlexGetHeightStratum(dm, dim, &pStart, &pEnd)); 1788 for (p = pStart; p < pEnd; p++) { 1789 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1790 if (coneSize) { 1791 *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1792 goto finish; 1793 } 1794 } 1795 1796 /* Check points at height < dim have cones */ 1797 for (h = 0; h < dim; h++) { 1798 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 1799 for (p = pStart; p < pEnd; p++) { 1800 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1801 if (!coneSize) { 1802 *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1803 goto finish; 1804 } 1805 } 1806 } 1807 } else if (depth == 1) { 1808 *interpolated = DMPLEX_INTERPOLATED_NONE; 1809 } else { 1810 *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1811 } 1812 finish: 1813 PetscFunctionReturn(0); 1814 } 1815 1816 /*@ 1817 DMPlexIsInterpolated - Find out to what extent the DMPlex is topologically interpolated. 1818 1819 Not Collective 1820 1821 Input Parameter: 1822 . dm - The DM object 1823 1824 Output Parameter: 1825 . interpolated - Flag whether the DM is interpolated 1826 1827 Level: intermediate 1828 1829 Notes: 1830 Unlike DMPlexIsInterpolatedCollective(), this is NOT collective 1831 so the results can be different on different ranks in special cases. 1832 However, DMPlexInterpolate() guarantees the result is the same on all. 1833 1834 Unlike DMPlexIsInterpolatedCollective(), this cannot return DMPLEX_INTERPOLATED_MIXED. 1835 1836 Developer Notes: 1837 Initially, plex->interpolated = DMPLEX_INTERPOLATED_INVALID. 1838 1839 If plex->interpolated == DMPLEX_INTERPOLATED_INVALID, DMPlexIsInterpolated_Internal() is called. 1840 It checks the actual topology and sets plex->interpolated on each rank separately to one of 1841 DMPLEX_INTERPOLATED_NONE, DMPLEX_INTERPOLATED_PARTIAL or DMPLEX_INTERPOLATED_FULL. 1842 1843 If plex->interpolated != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolated. 1844 1845 DMPlexInterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_FULL, 1846 and DMPlexUninterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_NONE. 1847 1848 .seealso: `DMPlexInterpolate()`, `DMPlexIsInterpolatedCollective()` 1849 @*/ 1850 PetscErrorCode DMPlexIsInterpolated(DM dm, DMPlexInterpolatedFlag *interpolated) { 1851 DM_Plex *plex = (DM_Plex *)dm->data; 1852 1853 PetscFunctionBegin; 1854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1855 PetscValidPointer(interpolated, 2); 1856 if (plex->interpolated < 0) { 1857 PetscCall(DMPlexIsInterpolated_Internal(dm, &plex->interpolated)); 1858 } else if (PetscDefined(USE_DEBUG)) { 1859 DMPlexInterpolatedFlag flg; 1860 1861 PetscCall(DMPlexIsInterpolated_Internal(dm, &flg)); 1862 PetscCheck(flg == plex->interpolated, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stashed DMPlexInterpolatedFlag %s is inconsistent with current %s", DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[flg]); 1863 } 1864 *interpolated = plex->interpolated; 1865 PetscFunctionReturn(0); 1866 } 1867 1868 /*@ 1869 DMPlexIsInterpolatedCollective - Find out to what extent the DMPlex is topologically interpolated (in collective manner). 1870 1871 Collective 1872 1873 Input Parameter: 1874 . dm - The DM object 1875 1876 Output Parameter: 1877 . interpolated - Flag whether the DM is interpolated 1878 1879 Level: intermediate 1880 1881 Notes: 1882 Unlike DMPlexIsInterpolated(), this is collective so the results are guaranteed to be the same on all ranks. 1883 1884 This function will return DMPLEX_INTERPOLATED_MIXED if the results of DMPlexIsInterpolated() are different on different ranks. 1885 1886 Developer Notes: 1887 Initially, plex->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID. 1888 1889 If plex->interpolatedCollective == DMPLEX_INTERPOLATED_INVALID, this function calls DMPlexIsInterpolated() which sets plex->interpolated. 1890 MPI_Allreduce() is then called and collectively consistent flag plex->interpolatedCollective is set and returned; 1891 if plex->interpolated varies on different ranks, plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED, 1892 otherwise sets plex->interpolatedCollective = plex->interpolated. 1893 1894 If plex->interpolatedCollective != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolatedCollective. 1895 1896 .seealso: `DMPlexInterpolate()`, `DMPlexIsInterpolated()` 1897 @*/ 1898 PetscErrorCode DMPlexIsInterpolatedCollective(DM dm, DMPlexInterpolatedFlag *interpolated) { 1899 DM_Plex *plex = (DM_Plex *)dm->data; 1900 PetscBool debug = PETSC_FALSE; 1901 1902 PetscFunctionBegin; 1903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1904 PetscValidPointer(interpolated, 2); 1905 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_is_interpolated_collective_debug", &debug, NULL)); 1906 if (plex->interpolatedCollective < 0) { 1907 DMPlexInterpolatedFlag min, max; 1908 MPI_Comm comm; 1909 1910 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1911 PetscCall(DMPlexIsInterpolated(dm, &plex->interpolatedCollective)); 1912 PetscCallMPI(MPI_Allreduce(&plex->interpolatedCollective, &min, 1, MPIU_ENUM, MPI_MIN, comm)); 1913 PetscCallMPI(MPI_Allreduce(&plex->interpolatedCollective, &max, 1, MPIU_ENUM, MPI_MAX, comm)); 1914 if (min != max) plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED; 1915 if (debug) { 1916 PetscMPIInt rank; 1917 1918 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1919 PetscCall(PetscSynchronizedPrintf(comm, "[%d] interpolated=%s interpolatedCollective=%s\n", rank, DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[plex->interpolatedCollective])); 1920 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT)); 1921 } 1922 } 1923 *interpolated = plex->interpolatedCollective; 1924 PetscFunctionReturn(0); 1925 } 1926