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