1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/petscfeimpl.h> 4 #include <petscsf.h> 5 #include <petscds.h> 6 7 /* hierarchy routines */ 8 9 /*@ 10 DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes. 11 12 Not Collective 13 14 Input Parameters: 15 + dm - The `DMPLEX` object 16 - ref - The reference tree `DMPLEX` object 17 18 Level: intermediate 19 20 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexGetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()` 21 @*/ 22 PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref) 23 { 24 DM_Plex *mesh = (DM_Plex *)dm->data; 25 26 PetscFunctionBegin; 27 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 28 if (ref) PetscValidHeaderSpecific(ref, DM_CLASSID, 2); 29 PetscCall(PetscObjectReference((PetscObject)ref)); 30 PetscCall(DMDestroy(&mesh->referenceTree)); 31 mesh->referenceTree = ref; 32 PetscFunctionReturn(PETSC_SUCCESS); 33 } 34 35 /*@ 36 DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes. 37 38 Not Collective 39 40 Input Parameters: 41 . dm - The `DMPLEX` object 42 43 Output Parameters: 44 . ref - The reference tree `DMPLEX` object 45 46 Level: intermediate 47 48 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetReferenceTree()`, `DMPlexCreateDefaultReferenceTree()` 49 @*/ 50 PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref) 51 { 52 DM_Plex *mesh = (DM_Plex *)dm->data; 53 54 PetscFunctionBegin; 55 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 56 PetscValidPointer(ref, 2); 57 *ref = mesh->referenceTree; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 61 static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) 62 { 63 PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert; 64 65 PetscFunctionBegin; 66 if (parentOrientA == parentOrientB) { 67 if (childOrientB) *childOrientB = childOrientA; 68 if (childB) *childB = childA; 69 PetscFunctionReturn(PETSC_SUCCESS); 70 } 71 for (dim = 0; dim < 3; dim++) { 72 PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd)); 73 if (parent >= dStart && parent <= dEnd) break; 74 } 75 PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim); 76 PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children"); 77 if (childA < dStart || childA >= dEnd) { 78 /* this is a lower-dimensional child: bootstrap */ 79 PetscInt size, i, sA = -1, sB, sOrientB, sConeSize; 80 const PetscInt *supp, *coneA, *coneB, *oA, *oB; 81 82 PetscCall(DMPlexGetSupportSize(dm, childA, &size)); 83 PetscCall(DMPlexGetSupport(dm, childA, &supp)); 84 85 /* find a point sA in supp(childA) that has the same parent */ 86 for (i = 0; i < size; i++) { 87 PetscInt sParent; 88 89 sA = supp[i]; 90 if (sA == parent) continue; 91 PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL)); 92 if (sParent == parent) break; 93 } 94 PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children"); 95 /* find out which point sB is in an equivalent position to sA under 96 * parentOrientB */ 97 PetscCall(DMPlexReferenceTreeGetChildSymmetry_Default(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB)); 98 PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize)); 99 PetscCall(DMPlexGetCone(dm, sA, &coneA)); 100 PetscCall(DMPlexGetCone(dm, sB, &coneB)); 101 PetscCall(DMPlexGetConeOrientation(dm, sA, &oA)); 102 PetscCall(DMPlexGetConeOrientation(dm, sB, &oB)); 103 /* step through the cone of sA in natural order */ 104 for (i = 0; i < sConeSize; i++) { 105 if (coneA[i] == childA) { 106 /* if childA is at position i in coneA, 107 * then we want the point that is at sOrientB*i in coneB */ 108 PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize); 109 if (childB) *childB = coneB[j]; 110 if (childOrientB) { 111 DMPolytopeType ct; 112 PetscInt oBtrue; 113 114 PetscCall(DMPlexGetConeSize(dm, childA, &coneSize)); 115 /* compose sOrientB and oB[j] */ 116 PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge"); 117 ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT; 118 /* we may have to flip an edge */ 119 oBtrue = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientation(ct, -1, oB[j]); 120 oBtrue = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue); 121 ABswap = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue); 122 *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap); 123 } 124 break; 125 } 126 } 127 PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch"); 128 PetscFunctionReturn(PETSC_SUCCESS); 129 } 130 /* get the cone size and symmetry swap */ 131 PetscCall(DMPlexGetConeSize(dm, parent, &coneSize)); 132 ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB); 133 if (dim == 2) { 134 /* orientations refer to cones: we want them to refer to vertices: 135 * if it's a rotation, they are the same, but if the order is reversed, a 136 * permutation that puts side i first does *not* put vertex i first */ 137 oAvert = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1); 138 oBvert = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1); 139 ABswapVert = DihedralSwap(coneSize, oAvert, oBvert); 140 } else { 141 ABswapVert = ABswap; 142 } 143 if (childB) { 144 /* assume that each child corresponds to a vertex, in the same order */ 145 PetscInt p, posA = -1, numChildren, i; 146 const PetscInt *children; 147 148 /* count which position the child is in */ 149 PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children)); 150 for (i = 0; i < numChildren; i++) { 151 p = children[i]; 152 if (p == childA) { 153 posA = i; 154 break; 155 } 156 } 157 if (posA >= coneSize) { 158 /* this is the triangle in the middle of a uniformly refined triangle: it 159 * is invariant */ 160 PetscCheck(dim == 2 && posA == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected a middle triangle, got something else"); 161 *childB = childA; 162 } else { 163 /* figure out position B by applying ABswapVert */ 164 PetscInt posB; 165 166 posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize); 167 if (childB) *childB = children[posB]; 168 } 169 } 170 if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap); 171 PetscFunctionReturn(PETSC_SUCCESS); 172 } 173 174 /*@ 175 DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another 176 177 Input Parameters: 178 + dm - the reference tree `DMPLEX` object 179 . parent - the parent point 180 . parentOrientA - the reference orientation for describing the parent 181 . childOrientA - the reference orientation for describing the child 182 . childA - the reference childID for describing the child 183 - parentOrientB - the new orientation for describing the parent 184 185 Output Parameters: 186 + childOrientB - if not `NULL`, set to the new orientation for describing the child 187 - childB - if not `NULL`, the new childID for describing the child 188 189 Level: developer 190 191 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetReferenceTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetTree()` 192 @*/ 193 PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) 194 { 195 DM_Plex *mesh = (DM_Plex *)dm->data; 196 197 PetscFunctionBegin; 198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 199 PetscCheck(mesh->getchildsymmetry, PETSC_COMM_SELF, PETSC_ERR_SUP, "DMPlexReferenceTreeGetChildSymmetry not implemented"); 200 PetscCall(mesh->getchildsymmetry(dm, parent, parentOrientA, childOrientA, childA, parentOrientB, childOrientB, childB)); 201 PetscFunctionReturn(PETSC_SUCCESS); 202 } 203 204 static PetscErrorCode DMPlexSetTree_Internal(DM, PetscSection, PetscInt *, PetscInt *, PetscBool, PetscBool); 205 206 PetscErrorCode DMPlexCreateReferenceTree_SetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[]) 207 { 208 PetscFunctionBegin; 209 PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_TRUE, PETSC_FALSE)); 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref) 214 { 215 MPI_Comm comm; 216 PetscInt dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs; 217 PetscInt *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts; 218 DMLabel identity, identityRef; 219 PetscSection unionSection, unionConeSection, parentSection; 220 PetscScalar *unionCoords; 221 IS perm; 222 223 PetscFunctionBegin; 224 comm = PetscObjectComm((PetscObject)K); 225 PetscCall(DMGetDimension(K, &dim)); 226 PetscCall(DMPlexGetChart(K, &pStart, &pEnd)); 227 PetscCall(DMGetLabel(K, labelName, &identity)); 228 PetscCall(DMGetLabel(Kref, labelName, &identityRef)); 229 PetscCall(DMPlexGetChart(Kref, &pRefStart, &pRefEnd)); 230 PetscCall(PetscSectionCreate(comm, &unionSection)); 231 PetscCall(PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart))); 232 /* count points that will go in the union */ 233 for (p = pStart; p < pEnd; p++) PetscCall(PetscSectionSetDof(unionSection, p - pStart, 1)); 234 for (p = pRefStart; p < pRefEnd; p++) { 235 PetscInt q, qSize; 236 PetscCall(DMLabelGetValue(identityRef, p, &q)); 237 PetscCall(DMLabelGetStratumSize(identityRef, q, &qSize)); 238 if (qSize > 1) PetscCall(PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1)); 239 } 240 PetscCall(PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart, &permvals)); 241 offset = 0; 242 /* stratify points in the union by topological dimension */ 243 for (d = 0; d <= dim; d++) { 244 PetscInt cStart, cEnd, c; 245 246 PetscCall(DMPlexGetHeightStratum(K, d, &cStart, &cEnd)); 247 for (c = cStart; c < cEnd; c++) permvals[offset++] = c; 248 249 PetscCall(DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd)); 250 for (c = cStart; c < cEnd; c++) permvals[offset++] = c + (pEnd - pStart); 251 } 252 PetscCall(ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm)); 253 PetscCall(PetscSectionSetPermutation(unionSection, perm)); 254 PetscCall(PetscSectionSetUp(unionSection)); 255 PetscCall(PetscSectionGetStorageSize(unionSection, &numUnionPoints)); 256 PetscCall(PetscMalloc2(numUnionPoints, &coneSizes, dim + 1, &numDimPoints)); 257 /* count dimension points */ 258 for (d = 0; d <= dim; d++) { 259 PetscInt cStart, cOff, cOff2; 260 PetscCall(DMPlexGetHeightStratum(K, d, &cStart, NULL)); 261 PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff)); 262 if (d < dim) { 263 PetscCall(DMPlexGetHeightStratum(K, d + 1, &cStart, NULL)); 264 PetscCall(PetscSectionGetOffset(unionSection, cStart - pStart, &cOff2)); 265 } else { 266 cOff2 = numUnionPoints; 267 } 268 numDimPoints[dim - d] = cOff2 - cOff; 269 } 270 PetscCall(PetscSectionCreate(comm, &unionConeSection)); 271 PetscCall(PetscSectionSetChart(unionConeSection, 0, numUnionPoints)); 272 /* count the cones in the union */ 273 for (p = pStart; p < pEnd; p++) { 274 PetscInt dof, uOff; 275 276 PetscCall(DMPlexGetConeSize(K, p, &dof)); 277 PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff)); 278 PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof)); 279 coneSizes[uOff] = dof; 280 } 281 for (p = pRefStart; p < pRefEnd; p++) { 282 PetscInt dof, uDof, uOff; 283 284 PetscCall(DMPlexGetConeSize(Kref, p, &dof)); 285 PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof)); 286 PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff)); 287 if (uDof) { 288 PetscCall(PetscSectionSetDof(unionConeSection, uOff, dof)); 289 coneSizes[uOff] = dof; 290 } 291 } 292 PetscCall(PetscSectionSetUp(unionConeSection)); 293 PetscCall(PetscSectionGetStorageSize(unionConeSection, &numCones)); 294 PetscCall(PetscMalloc2(numCones, &unionCones, numCones, &unionOrientations)); 295 /* write the cones in the union */ 296 for (p = pStart; p < pEnd; p++) { 297 PetscInt dof, uOff, c, cOff; 298 const PetscInt *cone, *orientation; 299 300 PetscCall(DMPlexGetConeSize(K, p, &dof)); 301 PetscCall(DMPlexGetCone(K, p, &cone)); 302 PetscCall(DMPlexGetConeOrientation(K, p, &orientation)); 303 PetscCall(PetscSectionGetOffset(unionSection, p - pStart, &uOff)); 304 PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff)); 305 for (c = 0; c < dof; c++) { 306 PetscInt e, eOff; 307 e = cone[c]; 308 PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff)); 309 unionCones[cOff + c] = eOff; 310 unionOrientations[cOff + c] = orientation[c]; 311 } 312 } 313 for (p = pRefStart; p < pRefEnd; p++) { 314 PetscInt dof, uDof, uOff, c, cOff; 315 const PetscInt *cone, *orientation; 316 317 PetscCall(DMPlexGetConeSize(Kref, p, &dof)); 318 PetscCall(DMPlexGetCone(Kref, p, &cone)); 319 PetscCall(DMPlexGetConeOrientation(Kref, p, &orientation)); 320 PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof)); 321 PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff)); 322 if (uDof) { 323 PetscCall(PetscSectionGetOffset(unionConeSection, uOff, &cOff)); 324 for (c = 0; c < dof; c++) { 325 PetscInt e, eOff, eDof; 326 327 e = cone[c]; 328 PetscCall(PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart), &eDof)); 329 if (eDof) { 330 PetscCall(PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff)); 331 } else { 332 PetscCall(DMLabelGetValue(identityRef, e, &e)); 333 PetscCall(PetscSectionGetOffset(unionSection, e - pStart, &eOff)); 334 } 335 unionCones[cOff + c] = eOff; 336 unionOrientations[cOff + c] = orientation[c]; 337 } 338 } 339 } 340 /* get the coordinates */ 341 { 342 PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff; 343 PetscSection KcoordsSec, KrefCoordsSec; 344 Vec KcoordsVec, KrefCoordsVec; 345 PetscScalar *Kcoords; 346 347 PetscCall(DMGetCoordinateSection(K, &KcoordsSec)); 348 PetscCall(DMGetCoordinatesLocal(K, &KcoordsVec)); 349 PetscCall(DMGetCoordinateSection(Kref, &KrefCoordsSec)); 350 PetscCall(DMGetCoordinatesLocal(Kref, &KrefCoordsVec)); 351 352 numVerts = numDimPoints[0]; 353 PetscCall(PetscMalloc1(numVerts * dim, &unionCoords)); 354 PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd)); 355 356 offset = 0; 357 for (v = vStart; v < vEnd; v++) { 358 PetscCall(PetscSectionGetOffset(unionSection, v - pStart, &vOff)); 359 PetscCall(VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords)); 360 for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d]; 361 offset++; 362 } 363 PetscCall(DMPlexGetDepthStratum(Kref, 0, &vRefStart, &vRefEnd)); 364 for (v = vRefStart; v < vRefEnd; v++) { 365 PetscCall(PetscSectionGetDof(unionSection, v - pRefStart + (pEnd - pStart), &vDof)); 366 PetscCall(PetscSectionGetOffset(unionSection, v - pRefStart + (pEnd - pStart), &vOff)); 367 PetscCall(VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords)); 368 if (vDof) { 369 for (d = 0; d < dim; d++) unionCoords[offset * dim + d] = Kcoords[d]; 370 offset++; 371 } 372 } 373 } 374 PetscCall(DMCreate(comm, ref)); 375 PetscCall(DMSetType(*ref, DMPLEX)); 376 PetscCall(DMSetDimension(*ref, dim)); 377 PetscCall(DMPlexCreateFromDAG(*ref, dim, numDimPoints, coneSizes, unionCones, unionOrientations, unionCoords)); 378 /* set the tree */ 379 PetscCall(PetscSectionCreate(comm, &parentSection)); 380 PetscCall(PetscSectionSetChart(parentSection, 0, numUnionPoints)); 381 for (p = pRefStart; p < pRefEnd; p++) { 382 PetscInt uDof, uOff; 383 384 PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof)); 385 PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff)); 386 if (uDof) PetscCall(PetscSectionSetDof(parentSection, uOff, 1)); 387 } 388 PetscCall(PetscSectionSetUp(parentSection)); 389 PetscCall(PetscSectionGetStorageSize(parentSection, &parentSize)); 390 PetscCall(PetscMalloc2(parentSize, &parents, parentSize, &childIDs)); 391 for (p = pRefStart; p < pRefEnd; p++) { 392 PetscInt uDof, uOff; 393 394 PetscCall(PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart), &uDof)); 395 PetscCall(PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart), &uOff)); 396 if (uDof) { 397 PetscInt pOff, parent, parentU; 398 PetscCall(PetscSectionGetOffset(parentSection, uOff, &pOff)); 399 PetscCall(DMLabelGetValue(identityRef, p, &parent)); 400 PetscCall(PetscSectionGetOffset(unionSection, parent - pStart, &parentU)); 401 parents[pOff] = parentU; 402 childIDs[pOff] = uOff; 403 } 404 } 405 PetscCall(DMPlexCreateReferenceTree_SetTree(*ref, parentSection, parents, childIDs)); 406 PetscCall(PetscSectionDestroy(&parentSection)); 407 PetscCall(PetscFree2(parents, childIDs)); 408 409 /* clean up */ 410 PetscCall(PetscSectionDestroy(&unionSection)); 411 PetscCall(PetscSectionDestroy(&unionConeSection)); 412 PetscCall(ISDestroy(&perm)); 413 PetscCall(PetscFree(unionCoords)); 414 PetscCall(PetscFree2(unionCones, unionOrientations)); 415 PetscCall(PetscFree2(coneSizes, numDimPoints)); 416 PetscFunctionReturn(PETSC_SUCCESS); 417 } 418 419 /*@ 420 DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement. 421 422 Collective 423 424 Input Parameters: 425 + comm - the MPI communicator 426 . dim - the spatial dimension 427 - simplex - Flag for simplex, otherwise use a tensor-product cell 428 429 Output Parameters: 430 . ref - the reference tree `DMPLEX` object 431 432 Level: intermediate 433 434 .seealso: `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()` 435 @*/ 436 PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref) 437 { 438 DM_Plex *mesh; 439 DM K, Kref; 440 PetscInt p, pStart, pEnd; 441 DMLabel identity; 442 443 PetscFunctionBegin; 444 #if 1 445 comm = PETSC_COMM_SELF; 446 #endif 447 /* create a reference element */ 448 PetscCall(DMPlexCreateReferenceCell(comm, DMPolytopeTypeSimpleShape(dim, simplex), &K)); 449 PetscCall(DMCreateLabel(K, "identity")); 450 PetscCall(DMGetLabel(K, "identity", &identity)); 451 PetscCall(DMPlexGetChart(K, &pStart, &pEnd)); 452 for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(identity, p, p)); 453 /* refine it */ 454 PetscCall(DMRefine(K, comm, &Kref)); 455 456 /* the reference tree is the union of these two, without duplicating 457 * points that appear in both */ 458 PetscCall(DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref)); 459 mesh = (DM_Plex *)(*ref)->data; 460 mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default; 461 PetscCall(DMDestroy(&K)); 462 PetscCall(DMDestroy(&Kref)); 463 PetscFunctionReturn(PETSC_SUCCESS); 464 } 465 466 static PetscErrorCode DMPlexTreeSymmetrize(DM dm) 467 { 468 DM_Plex *mesh = (DM_Plex *)dm->data; 469 PetscSection childSec, pSec; 470 PetscInt p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT; 471 PetscInt *offsets, *children, pStart, pEnd; 472 473 PetscFunctionBegin; 474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 475 PetscCall(PetscSectionDestroy(&mesh->childSection)); 476 PetscCall(PetscFree(mesh->children)); 477 pSec = mesh->parentSection; 478 if (!pSec) PetscFunctionReturn(PETSC_SUCCESS); 479 PetscCall(PetscSectionGetStorageSize(pSec, &pSize)); 480 for (p = 0; p < pSize; p++) { 481 PetscInt par = mesh->parents[p]; 482 483 parMax = PetscMax(parMax, par + 1); 484 parMin = PetscMin(parMin, par); 485 } 486 if (parMin > parMax) { 487 parMin = -1; 488 parMax = -1; 489 } 490 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)pSec), &childSec)); 491 PetscCall(PetscSectionSetChart(childSec, parMin, parMax)); 492 for (p = 0; p < pSize; p++) { 493 PetscInt par = mesh->parents[p]; 494 495 PetscCall(PetscSectionAddDof(childSec, par, 1)); 496 } 497 PetscCall(PetscSectionSetUp(childSec)); 498 PetscCall(PetscSectionGetStorageSize(childSec, &cSize)); 499 PetscCall(PetscMalloc1(cSize, &children)); 500 PetscCall(PetscCalloc1(parMax - parMin, &offsets)); 501 PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd)); 502 for (p = pStart; p < pEnd; p++) { 503 PetscInt dof, off, i; 504 505 PetscCall(PetscSectionGetDof(pSec, p, &dof)); 506 PetscCall(PetscSectionGetOffset(pSec, p, &off)); 507 for (i = 0; i < dof; i++) { 508 PetscInt par = mesh->parents[off + i], cOff; 509 510 PetscCall(PetscSectionGetOffset(childSec, par, &cOff)); 511 children[cOff + offsets[par - parMin]++] = p; 512 } 513 } 514 mesh->childSection = childSec; 515 mesh->children = children; 516 PetscCall(PetscFree(offsets)); 517 PetscFunctionReturn(PETSC_SUCCESS); 518 } 519 520 static PetscErrorCode AnchorsFlatten(PetscSection section, IS is, PetscSection *sectionNew, IS *isNew) 521 { 522 PetscInt pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL; 523 const PetscInt *vals; 524 PetscSection secNew; 525 PetscBool anyNew, globalAnyNew; 526 PetscBool compress; 527 528 PetscFunctionBegin; 529 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 530 PetscCall(ISGetLocalSize(is, &size)); 531 PetscCall(ISGetIndices(is, &vals)); 532 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secNew)); 533 PetscCall(PetscSectionSetChart(secNew, pStart, pEnd)); 534 for (i = 0; i < size; i++) { 535 PetscInt dof; 536 537 p = vals[i]; 538 if (p < pStart || p >= pEnd) continue; 539 PetscCall(PetscSectionGetDof(section, p, &dof)); 540 if (dof) break; 541 } 542 if (i == size) { 543 PetscCall(PetscSectionSetUp(secNew)); 544 anyNew = PETSC_FALSE; 545 compress = PETSC_FALSE; 546 sizeNew = 0; 547 } else { 548 anyNew = PETSC_TRUE; 549 for (p = pStart; p < pEnd; p++) { 550 PetscInt dof, off; 551 552 PetscCall(PetscSectionGetDof(section, p, &dof)); 553 PetscCall(PetscSectionGetOffset(section, p, &off)); 554 for (i = 0; i < dof; i++) { 555 PetscInt q = vals[off + i], qDof = 0; 556 557 if (q >= pStart && q < pEnd) PetscCall(PetscSectionGetDof(section, q, &qDof)); 558 if (qDof) PetscCall(PetscSectionAddDof(secNew, p, qDof)); 559 else PetscCall(PetscSectionAddDof(secNew, p, 1)); 560 } 561 } 562 PetscCall(PetscSectionSetUp(secNew)); 563 PetscCall(PetscSectionGetStorageSize(secNew, &sizeNew)); 564 PetscCall(PetscMalloc1(sizeNew, &valsNew)); 565 compress = PETSC_FALSE; 566 for (p = pStart; p < pEnd; p++) { 567 PetscInt dof, off, count, offNew, dofNew; 568 569 PetscCall(PetscSectionGetDof(section, p, &dof)); 570 PetscCall(PetscSectionGetOffset(section, p, &off)); 571 PetscCall(PetscSectionGetDof(secNew, p, &dofNew)); 572 PetscCall(PetscSectionGetOffset(secNew, p, &offNew)); 573 count = 0; 574 for (i = 0; i < dof; i++) { 575 PetscInt q = vals[off + i], qDof = 0, qOff = 0, j; 576 577 if (q >= pStart && q < pEnd) { 578 PetscCall(PetscSectionGetDof(section, q, &qDof)); 579 PetscCall(PetscSectionGetOffset(section, q, &qOff)); 580 } 581 if (qDof) { 582 PetscInt oldCount = count; 583 584 for (j = 0; j < qDof; j++) { 585 PetscInt k, r = vals[qOff + j]; 586 587 for (k = 0; k < oldCount; k++) { 588 if (valsNew[offNew + k] == r) break; 589 } 590 if (k == oldCount) valsNew[offNew + count++] = r; 591 } 592 } else { 593 PetscInt k, oldCount = count; 594 595 for (k = 0; k < oldCount; k++) { 596 if (valsNew[offNew + k] == q) break; 597 } 598 if (k == oldCount) valsNew[offNew + count++] = q; 599 } 600 } 601 if (count < dofNew) { 602 PetscCall(PetscSectionSetDof(secNew, p, count)); 603 compress = PETSC_TRUE; 604 } 605 } 606 } 607 PetscCall(ISRestoreIndices(is, &vals)); 608 PetscCall(MPIU_Allreduce(&anyNew, &globalAnyNew, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew))); 609 if (!globalAnyNew) { 610 PetscCall(PetscSectionDestroy(&secNew)); 611 *sectionNew = NULL; 612 *isNew = NULL; 613 } else { 614 PetscBool globalCompress; 615 616 PetscCall(MPIU_Allreduce(&compress, &globalCompress, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)secNew))); 617 if (compress) { 618 PetscSection secComp; 619 PetscInt *valsComp = NULL; 620 621 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), &secComp)); 622 PetscCall(PetscSectionSetChart(secComp, pStart, pEnd)); 623 for (p = pStart; p < pEnd; p++) { 624 PetscInt dof; 625 626 PetscCall(PetscSectionGetDof(secNew, p, &dof)); 627 PetscCall(PetscSectionSetDof(secComp, p, dof)); 628 } 629 PetscCall(PetscSectionSetUp(secComp)); 630 PetscCall(PetscSectionGetStorageSize(secComp, &sizeNew)); 631 PetscCall(PetscMalloc1(sizeNew, &valsComp)); 632 for (p = pStart; p < pEnd; p++) { 633 PetscInt dof, off, offNew, j; 634 635 PetscCall(PetscSectionGetDof(secNew, p, &dof)); 636 PetscCall(PetscSectionGetOffset(secNew, p, &off)); 637 PetscCall(PetscSectionGetOffset(secComp, p, &offNew)); 638 for (j = 0; j < dof; j++) valsComp[offNew + j] = valsNew[off + j]; 639 } 640 PetscCall(PetscSectionDestroy(&secNew)); 641 secNew = secComp; 642 PetscCall(PetscFree(valsNew)); 643 valsNew = valsComp; 644 } 645 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), sizeNew, valsNew, PETSC_OWN_POINTER, isNew)); 646 } 647 PetscFunctionReturn(PETSC_SUCCESS); 648 } 649 650 static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm) 651 { 652 PetscInt p, pStart, pEnd, *anchors, size; 653 PetscInt aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT; 654 PetscSection aSec; 655 DMLabel canonLabel; 656 IS aIS; 657 658 PetscFunctionBegin; 659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 660 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 661 PetscCall(DMGetLabel(dm, "canonical", &canonLabel)); 662 for (p = pStart; p < pEnd; p++) { 663 PetscInt parent; 664 665 if (canonLabel) { 666 PetscInt canon; 667 668 PetscCall(DMLabelGetValue(canonLabel, p, &canon)); 669 if (p != canon) continue; 670 } 671 PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL)); 672 if (parent != p) { 673 aMin = PetscMin(aMin, p); 674 aMax = PetscMax(aMax, p + 1); 675 } 676 } 677 if (aMin > aMax) { 678 aMin = -1; 679 aMax = -1; 680 } 681 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &aSec)); 682 PetscCall(PetscSectionSetChart(aSec, aMin, aMax)); 683 for (p = aMin; p < aMax; p++) { 684 PetscInt parent, ancestor = p; 685 686 if (canonLabel) { 687 PetscInt canon; 688 689 PetscCall(DMLabelGetValue(canonLabel, p, &canon)); 690 if (p != canon) continue; 691 } 692 PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL)); 693 while (parent != ancestor) { 694 ancestor = parent; 695 PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL)); 696 } 697 if (ancestor != p) { 698 PetscInt closureSize, *closure = NULL; 699 700 PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure)); 701 PetscCall(PetscSectionSetDof(aSec, p, closureSize)); 702 PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure)); 703 } 704 } 705 PetscCall(PetscSectionSetUp(aSec)); 706 PetscCall(PetscSectionGetStorageSize(aSec, &size)); 707 PetscCall(PetscMalloc1(size, &anchors)); 708 for (p = aMin; p < aMax; p++) { 709 PetscInt parent, ancestor = p; 710 711 if (canonLabel) { 712 PetscInt canon; 713 714 PetscCall(DMLabelGetValue(canonLabel, p, &canon)); 715 if (p != canon) continue; 716 } 717 PetscCall(DMPlexGetTreeParent(dm, p, &parent, NULL)); 718 while (parent != ancestor) { 719 ancestor = parent; 720 PetscCall(DMPlexGetTreeParent(dm, ancestor, &parent, NULL)); 721 } 722 if (ancestor != p) { 723 PetscInt j, closureSize, *closure = NULL, aOff; 724 725 PetscCall(PetscSectionGetOffset(aSec, p, &aOff)); 726 727 PetscCall(DMPlexGetTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure)); 728 for (j = 0; j < closureSize; j++) anchors[aOff + j] = closure[2 * j]; 729 PetscCall(DMPlexRestoreTransitiveClosure(dm, ancestor, PETSC_TRUE, &closureSize, &closure)); 730 } 731 } 732 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, anchors, PETSC_OWN_POINTER, &aIS)); 733 { 734 PetscSection aSecNew = aSec; 735 IS aISNew = aIS; 736 737 PetscCall(PetscObjectReference((PetscObject)aSec)); 738 PetscCall(PetscObjectReference((PetscObject)aIS)); 739 while (aSecNew) { 740 PetscCall(PetscSectionDestroy(&aSec)); 741 PetscCall(ISDestroy(&aIS)); 742 aSec = aSecNew; 743 aIS = aISNew; 744 aSecNew = NULL; 745 aISNew = NULL; 746 PetscCall(AnchorsFlatten(aSec, aIS, &aSecNew, &aISNew)); 747 } 748 } 749 PetscCall(DMPlexSetAnchors(dm, aSec, aIS)); 750 PetscCall(PetscSectionDestroy(&aSec)); 751 PetscCall(ISDestroy(&aIS)); 752 PetscFunctionReturn(PETSC_SUCCESS); 753 } 754 755 static PetscErrorCode DMPlexGetTrueSupportSize(DM dm, PetscInt p, PetscInt *dof, PetscInt *numTrueSupp) 756 { 757 PetscFunctionBegin; 758 if (numTrueSupp[p] == -1) { 759 PetscInt i, alldof; 760 const PetscInt *supp; 761 PetscInt count = 0; 762 763 PetscCall(DMPlexGetSupportSize(dm, p, &alldof)); 764 PetscCall(DMPlexGetSupport(dm, p, &supp)); 765 for (i = 0; i < alldof; i++) { 766 PetscInt q = supp[i], numCones, j; 767 const PetscInt *cone; 768 769 PetscCall(DMPlexGetConeSize(dm, q, &numCones)); 770 PetscCall(DMPlexGetCone(dm, q, &cone)); 771 for (j = 0; j < numCones; j++) { 772 if (cone[j] == p) break; 773 } 774 if (j < numCones) count++; 775 } 776 numTrueSupp[p] = count; 777 } 778 *dof = numTrueSupp[p]; 779 PetscFunctionReturn(PETSC_SUCCESS); 780 } 781 782 static PetscErrorCode DMPlexTreeExchangeSupports(DM dm) 783 { 784 DM_Plex *mesh = (DM_Plex *)dm->data; 785 PetscSection newSupportSection; 786 PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth; 787 PetscInt *numTrueSupp; 788 PetscInt *offsets; 789 790 PetscFunctionBegin; 791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 792 /* symmetrize the hierarchy */ 793 PetscCall(DMPlexGetDepth(dm, &depth)); 794 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)), &newSupportSection)); 795 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 796 PetscCall(PetscSectionSetChart(newSupportSection, pStart, pEnd)); 797 PetscCall(PetscCalloc1(pEnd, &offsets)); 798 PetscCall(PetscMalloc1(pEnd, &numTrueSupp)); 799 for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1; 800 /* if a point is in the (true) support of q, it should be in the support of 801 * parent(q) */ 802 for (d = 0; d <= depth; d++) { 803 PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd)); 804 for (p = pStart; p < pEnd; ++p) { 805 PetscInt dof, q, qdof, parent; 806 807 PetscCall(DMPlexGetTrueSupportSize(dm, p, &dof, numTrueSupp)); 808 PetscCall(PetscSectionAddDof(newSupportSection, p, dof)); 809 q = p; 810 PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL)); 811 while (parent != q && parent >= pStart && parent < pEnd) { 812 q = parent; 813 814 PetscCall(DMPlexGetTrueSupportSize(dm, q, &qdof, numTrueSupp)); 815 PetscCall(PetscSectionAddDof(newSupportSection, p, qdof)); 816 PetscCall(PetscSectionAddDof(newSupportSection, q, dof)); 817 PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL)); 818 } 819 } 820 } 821 PetscCall(PetscSectionSetUp(newSupportSection)); 822 PetscCall(PetscSectionGetStorageSize(newSupportSection, &newSize)); 823 PetscCall(PetscMalloc1(newSize, &newSupports)); 824 for (d = 0; d <= depth; d++) { 825 PetscCall(DMPlexGetHeightStratum(dm, d, &pStart, &pEnd)); 826 for (p = pStart; p < pEnd; p++) { 827 PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent; 828 829 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 830 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 831 PetscCall(PetscSectionGetDof(newSupportSection, p, &newDof)); 832 PetscCall(PetscSectionGetOffset(newSupportSection, p, &newOff)); 833 for (i = 0; i < dof; i++) { 834 PetscInt numCones, j; 835 const PetscInt *cone; 836 PetscInt q = mesh->supports[off + i]; 837 838 PetscCall(DMPlexGetConeSize(dm, q, &numCones)); 839 PetscCall(DMPlexGetCone(dm, q, &cone)); 840 for (j = 0; j < numCones; j++) { 841 if (cone[j] == p) break; 842 } 843 if (j < numCones) newSupports[newOff + offsets[p]++] = q; 844 } 845 846 q = p; 847 PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL)); 848 while (parent != q && parent >= pStart && parent < pEnd) { 849 q = parent; 850 PetscCall(PetscSectionGetDof(mesh->supportSection, q, &qdof)); 851 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &qoff)); 852 PetscCall(PetscSectionGetOffset(newSupportSection, q, &newqOff)); 853 for (i = 0; i < qdof; i++) { 854 PetscInt numCones, j; 855 const PetscInt *cone; 856 PetscInt r = mesh->supports[qoff + i]; 857 858 PetscCall(DMPlexGetConeSize(dm, r, &numCones)); 859 PetscCall(DMPlexGetCone(dm, r, &cone)); 860 for (j = 0; j < numCones; j++) { 861 if (cone[j] == q) break; 862 } 863 if (j < numCones) newSupports[newOff + offsets[p]++] = r; 864 } 865 for (i = 0; i < dof; i++) { 866 PetscInt numCones, j; 867 const PetscInt *cone; 868 PetscInt r = mesh->supports[off + i]; 869 870 PetscCall(DMPlexGetConeSize(dm, r, &numCones)); 871 PetscCall(DMPlexGetCone(dm, r, &cone)); 872 for (j = 0; j < numCones; j++) { 873 if (cone[j] == p) break; 874 } 875 if (j < numCones) newSupports[newqOff + offsets[q]++] = r; 876 } 877 PetscCall(DMPlexGetTreeParent(dm, q, &parent, NULL)); 878 } 879 } 880 } 881 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 882 mesh->supportSection = newSupportSection; 883 PetscCall(PetscFree(mesh->supports)); 884 mesh->supports = newSupports; 885 PetscCall(PetscFree(offsets)); 886 PetscCall(PetscFree(numTrueSupp)); 887 888 PetscFunctionReturn(PETSC_SUCCESS); 889 } 890 891 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM, PetscSection, PetscSection, Mat); 892 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM, PetscSection, PetscSection, Mat); 893 894 static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports) 895 { 896 DM_Plex *mesh = (DM_Plex *)dm->data; 897 DM refTree; 898 PetscInt size; 899 900 PetscFunctionBegin; 901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 902 PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2); 903 PetscCall(PetscObjectReference((PetscObject)parentSection)); 904 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 905 mesh->parentSection = parentSection; 906 PetscCall(PetscSectionGetStorageSize(parentSection, &size)); 907 if (parents != mesh->parents) { 908 PetscCall(PetscFree(mesh->parents)); 909 PetscCall(PetscMalloc1(size, &mesh->parents)); 910 PetscCall(PetscArraycpy(mesh->parents, parents, size)); 911 } 912 if (childIDs != mesh->childIDs) { 913 PetscCall(PetscFree(mesh->childIDs)); 914 PetscCall(PetscMalloc1(size, &mesh->childIDs)); 915 PetscCall(PetscArraycpy(mesh->childIDs, childIDs, size)); 916 } 917 PetscCall(DMPlexGetReferenceTree(dm, &refTree)); 918 if (refTree) { 919 DMLabel canonLabel; 920 921 PetscCall(DMGetLabel(refTree, "canonical", &canonLabel)); 922 if (canonLabel) { 923 PetscInt i; 924 925 for (i = 0; i < size; i++) { 926 PetscInt canon; 927 PetscCall(DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon)); 928 if (canon >= 0) mesh->childIDs[i] = canon; 929 } 930 } 931 mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference; 932 } else { 933 mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct; 934 } 935 PetscCall(DMPlexTreeSymmetrize(dm)); 936 if (computeCanonical) { 937 PetscInt d, dim; 938 939 /* add the canonical label */ 940 PetscCall(DMGetDimension(dm, &dim)); 941 PetscCall(DMCreateLabel(dm, "canonical")); 942 for (d = 0; d <= dim; d++) { 943 PetscInt p, dStart, dEnd, canon = -1, cNumChildren; 944 const PetscInt *cChildren; 945 946 PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd)); 947 for (p = dStart; p < dEnd; p++) { 948 PetscCall(DMPlexGetTreeChildren(dm, p, &cNumChildren, &cChildren)); 949 if (cNumChildren) { 950 canon = p; 951 break; 952 } 953 } 954 if (canon == -1) continue; 955 for (p = dStart; p < dEnd; p++) { 956 PetscInt numChildren, i; 957 const PetscInt *children; 958 959 PetscCall(DMPlexGetTreeChildren(dm, p, &numChildren, &children)); 960 if (numChildren) { 961 PetscCheck(numChildren == cNumChildren, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "All parent points in a stratum should have the same number of children: %" PetscInt_FMT " != %" PetscInt_FMT, numChildren, cNumChildren); 962 PetscCall(DMSetLabelValue(dm, "canonical", p, canon)); 963 for (i = 0; i < numChildren; i++) PetscCall(DMSetLabelValue(dm, "canonical", children[i], cChildren[i])); 964 } 965 } 966 } 967 } 968 if (exchangeSupports) PetscCall(DMPlexTreeExchangeSupports(dm)); 969 mesh->createanchors = DMPlexCreateAnchors_Tree; 970 /* reset anchors */ 971 PetscCall(DMPlexSetAnchors(dm, NULL, NULL)); 972 PetscFunctionReturn(PETSC_SUCCESS); 973 } 974 975 /*@ 976 DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points. This routine also creates 977 the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its 978 tree root. 979 980 Collective 981 982 Input Parameters: 983 + dm - the `DMPLEX` object 984 . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section 985 offset indexes the parent and childID list; the reference count of parentSection is incremented 986 . parents - a list of the point parents; copied, can be destroyed 987 - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then 988 the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed 989 990 Level: intermediate 991 992 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()` 993 @*/ 994 PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[]) 995 { 996 PetscFunctionBegin; 997 PetscCall(DMPlexSetTree_Internal(dm, parentSection, parents, childIDs, PETSC_FALSE, PETSC_TRUE)); 998 PetscFunctionReturn(PETSC_SUCCESS); 999 } 1000 1001 /*@ 1002 DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points. 1003 Collective 1004 1005 Input Parameter: 1006 . dm - the `DMPLEX` object 1007 1008 Output Parameters: 1009 + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section 1010 offset indexes the parent and childID list 1011 . parents - a list of the point parents 1012 . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then 1013 the child corresponds to the point in the reference tree with index childID 1014 . childSection - the inverse of the parent section 1015 - children - a list of the point children 1016 1017 Level: intermediate 1018 1019 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`,`DMPlexSetTree()`, `DMPlexSetReferenceTree()`, `DMPlexSetAnchors()`, `DMPlexGetTreeParent()`, `DMPlexGetTreeChildren()` 1020 @*/ 1021 PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[]) 1022 { 1023 DM_Plex *mesh = (DM_Plex *)dm->data; 1024 1025 PetscFunctionBegin; 1026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1027 if (parentSection) *parentSection = mesh->parentSection; 1028 if (parents) *parents = mesh->parents; 1029 if (childIDs) *childIDs = mesh->childIDs; 1030 if (childSection) *childSection = mesh->childSection; 1031 if (children) *children = mesh->children; 1032 PetscFunctionReturn(PETSC_SUCCESS); 1033 } 1034 1035 /*@ 1036 DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the DAG) 1037 1038 Input Parameters: 1039 + dm - the `DMPLEX` object 1040 - point - the query point 1041 1042 Output Parameters: 1043 + parent - if not `NULL`, set to the parent of the point, or the point itself if the point does not have a parent 1044 - childID - if not `NULL`, set to the child ID of the point with respect to its parent, or 0 if the point 1045 does not have a parent 1046 1047 Level: intermediate 1048 1049 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeChildren()` 1050 @*/ 1051 PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID) 1052 { 1053 DM_Plex *mesh = (DM_Plex *)dm->data; 1054 PetscSection pSec; 1055 1056 PetscFunctionBegin; 1057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1058 pSec = mesh->parentSection; 1059 if (pSec && point >= pSec->pStart && point < pSec->pEnd) { 1060 PetscInt dof; 1061 1062 PetscCall(PetscSectionGetDof(pSec, point, &dof)); 1063 if (dof) { 1064 PetscInt off; 1065 1066 PetscCall(PetscSectionGetOffset(pSec, point, &off)); 1067 if (parent) *parent = mesh->parents[off]; 1068 if (childID) *childID = mesh->childIDs[off]; 1069 PetscFunctionReturn(PETSC_SUCCESS); 1070 } 1071 } 1072 if (parent) *parent = point; 1073 if (childID) *childID = 0; 1074 PetscFunctionReturn(PETSC_SUCCESS); 1075 } 1076 1077 /*@C 1078 DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the DAG) 1079 1080 Input Parameters: 1081 + dm - the `DMPLEX` object 1082 - point - the query point 1083 1084 Output Parameters: 1085 + numChildren - if not `NULL`, set to the number of children 1086 - children - if not `NULL`, set to a list children, or set to `NULL` if the point has no children 1087 1088 Level: intermediate 1089 1090 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetTree()`, `DMPlexGetTree()`, `DMPlexGetTreeParent()` 1091 @*/ 1092 PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[]) 1093 { 1094 DM_Plex *mesh = (DM_Plex *)dm->data; 1095 PetscSection childSec; 1096 PetscInt dof = 0; 1097 1098 PetscFunctionBegin; 1099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1100 childSec = mesh->childSection; 1101 if (childSec && point >= childSec->pStart && point < childSec->pEnd) PetscCall(PetscSectionGetDof(childSec, point, &dof)); 1102 if (numChildren) *numChildren = dof; 1103 if (children) { 1104 if (dof) { 1105 PetscInt off; 1106 1107 PetscCall(PetscSectionGetOffset(childSec, point, &off)); 1108 *children = &mesh->children[off]; 1109 } else { 1110 *children = NULL; 1111 } 1112 } 1113 PetscFunctionReturn(PETSC_SUCCESS); 1114 } 1115 1116 static PetscErrorCode EvaluateBasis(PetscSpace space, PetscInt nBasis, PetscInt nFunctionals, PetscInt nComps, PetscInt nPoints, const PetscInt *pointsPerFn, const PetscReal *points, const PetscReal *weights, PetscReal *work, Mat basisAtPoints) 1117 { 1118 PetscInt f, b, p, c, offset, qPoints; 1119 1120 PetscFunctionBegin; 1121 PetscCall(PetscSpaceEvaluate(space, nPoints, points, work, NULL, NULL)); 1122 for (f = 0, offset = 0; f < nFunctionals; f++) { 1123 qPoints = pointsPerFn[f]; 1124 for (b = 0; b < nBasis; b++) { 1125 PetscScalar val = 0.; 1126 1127 for (p = 0; p < qPoints; p++) { 1128 for (c = 0; c < nComps; c++) val += work[((offset + p) * nBasis + b) * nComps + c] * weights[(offset + p) * nComps + c]; 1129 } 1130 PetscCall(MatSetValue(basisAtPoints, b, f, val, INSERT_VALUES)); 1131 } 1132 offset += qPoints; 1133 } 1134 PetscCall(MatAssemblyBegin(basisAtPoints, MAT_FINAL_ASSEMBLY)); 1135 PetscCall(MatAssemblyEnd(basisAtPoints, MAT_FINAL_ASSEMBLY)); 1136 PetscFunctionReturn(PETSC_SUCCESS); 1137 } 1138 1139 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat) 1140 { 1141 PetscDS ds; 1142 PetscInt spdim; 1143 PetscInt numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd; 1144 const PetscInt *anchors; 1145 PetscSection aSec; 1146 PetscReal *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent; 1147 IS aIS; 1148 1149 PetscFunctionBegin; 1150 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1151 PetscCall(DMGetDS(dm, &ds)); 1152 PetscCall(PetscDSGetNumFields(ds, &numFields)); 1153 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1154 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 1155 PetscCall(ISGetIndices(aIS, &anchors)); 1156 PetscCall(PetscSectionGetChart(cSec, &conStart, &conEnd)); 1157 PetscCall(DMGetDimension(dm, &spdim)); 1158 PetscCall(PetscMalloc6(spdim, &v0, spdim, &v0parent, spdim, &vtmp, spdim * spdim, &J, spdim * spdim, &Jparent, spdim * spdim, &invJparent)); 1159 1160 for (f = 0; f < numFields; f++) { 1161 PetscObject disc; 1162 PetscClassId id; 1163 PetscSpace bspace; 1164 PetscDualSpace dspace; 1165 PetscInt i, j, k, nPoints, Nc, offset; 1166 PetscInt fSize, maxDof; 1167 PetscReal *weights, *pointsRef, *pointsReal, *work; 1168 PetscScalar *scwork; 1169 const PetscScalar *X; 1170 PetscInt *sizes, *workIndRow, *workIndCol; 1171 Mat Amat, Bmat, Xmat; 1172 const PetscInt *numDof = NULL; 1173 const PetscInt ***perms = NULL; 1174 const PetscScalar ***flips = NULL; 1175 1176 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 1177 PetscCall(PetscObjectGetClassId(disc, &id)); 1178 if (id == PETSCFE_CLASSID) { 1179 PetscFE fe = (PetscFE)disc; 1180 1181 PetscCall(PetscFEGetBasisSpace(fe, &bspace)); 1182 PetscCall(PetscFEGetDualSpace(fe, &dspace)); 1183 PetscCall(PetscDualSpaceGetDimension(dspace, &fSize)); 1184 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1185 } else if (id == PETSCFV_CLASSID) { 1186 PetscFV fv = (PetscFV)disc; 1187 1188 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1189 PetscCall(PetscSpaceCreate(PetscObjectComm((PetscObject)fv), &bspace)); 1190 PetscCall(PetscSpaceSetType(bspace, PETSCSPACEPOLYNOMIAL)); 1191 PetscCall(PetscSpaceSetDegree(bspace, 0, PETSC_DETERMINE)); 1192 PetscCall(PetscSpaceSetNumComponents(bspace, Nc)); 1193 PetscCall(PetscSpaceSetNumVariables(bspace, spdim)); 1194 PetscCall(PetscSpaceSetUp(bspace)); 1195 PetscCall(PetscFVGetDualSpace(fv, &dspace)); 1196 PetscCall(PetscDualSpaceGetDimension(dspace, &fSize)); 1197 } else SETERRQ(PetscObjectComm(disc), PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id); 1198 PetscCall(PetscDualSpaceGetNumDof(dspace, &numDof)); 1199 for (i = 0, maxDof = 0; i <= spdim; i++) maxDof = PetscMax(maxDof, numDof[i]); 1200 PetscCall(PetscDualSpaceGetSymmetries(dspace, &perms, &flips)); 1201 1202 PetscCall(MatCreate(PETSC_COMM_SELF, &Amat)); 1203 PetscCall(MatSetSizes(Amat, fSize, fSize, fSize, fSize)); 1204 PetscCall(MatSetType(Amat, MATSEQDENSE)); 1205 PetscCall(MatSetUp(Amat)); 1206 PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Bmat)); 1207 PetscCall(MatDuplicate(Amat, MAT_DO_NOT_COPY_VALUES, &Xmat)); 1208 nPoints = 0; 1209 for (i = 0; i < fSize; i++) { 1210 PetscInt qPoints, thisNc; 1211 PetscQuadrature quad; 1212 1213 PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad)); 1214 PetscCall(PetscQuadratureGetData(quad, NULL, &thisNc, &qPoints, NULL, NULL)); 1215 PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc); 1216 nPoints += qPoints; 1217 } 1218 PetscCall(PetscMalloc7(fSize, &sizes, nPoints * Nc, &weights, spdim * nPoints, &pointsRef, spdim * nPoints, &pointsReal, nPoints * fSize * Nc, &work, maxDof, &workIndRow, maxDof, &workIndCol)); 1219 PetscCall(PetscMalloc1(maxDof * maxDof, &scwork)); 1220 offset = 0; 1221 for (i = 0; i < fSize; i++) { 1222 PetscInt qPoints; 1223 const PetscReal *p, *w; 1224 PetscQuadrature quad; 1225 1226 PetscCall(PetscDualSpaceGetFunctional(dspace, i, &quad)); 1227 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &qPoints, &p, &w)); 1228 PetscCall(PetscArraycpy(weights + Nc * offset, w, Nc * qPoints)); 1229 PetscCall(PetscArraycpy(pointsRef + spdim * offset, p, spdim * qPoints)); 1230 sizes[i] = qPoints; 1231 offset += qPoints; 1232 } 1233 PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsRef, weights, work, Amat)); 1234 PetscCall(MatLUFactor(Amat, NULL, NULL, NULL)); 1235 for (c = cStart; c < cEnd; c++) { 1236 PetscInt parent; 1237 PetscInt closureSize, closureSizeP, *closure = NULL, *closureP = NULL; 1238 PetscInt *childOffsets, *parentOffsets; 1239 1240 PetscCall(DMPlexGetTreeParent(dm, c, &parent, NULL)); 1241 if (parent == c) continue; 1242 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1243 for (i = 0; i < closureSize; i++) { 1244 PetscInt p = closure[2 * i]; 1245 PetscInt conDof; 1246 1247 if (p < conStart || p >= conEnd) continue; 1248 if (numFields) { 1249 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof)); 1250 } else { 1251 PetscCall(PetscSectionGetDof(cSec, p, &conDof)); 1252 } 1253 if (conDof) break; 1254 } 1255 if (i == closureSize) { 1256 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1257 continue; 1258 } 1259 1260 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ)); 1261 PetscCall(DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent)); 1262 for (i = 0; i < nPoints; i++) { 1263 const PetscReal xi0[3] = {-1., -1., -1.}; 1264 1265 CoordinatesRefToReal(spdim, spdim, xi0, v0, J, &pointsRef[i * spdim], vtmp); 1266 CoordinatesRealToRef(spdim, spdim, xi0, v0parent, invJparent, vtmp, &pointsReal[i * spdim]); 1267 } 1268 PetscCall(EvaluateBasis(bspace, fSize, fSize, Nc, nPoints, sizes, pointsReal, weights, work, Bmat)); 1269 PetscCall(MatMatSolve(Amat, Bmat, Xmat)); 1270 PetscCall(MatDenseGetArrayRead(Xmat, &X)); 1271 PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP)); 1272 PetscCall(PetscMalloc2(closureSize + 1, &childOffsets, closureSizeP + 1, &parentOffsets)); 1273 childOffsets[0] = 0; 1274 for (i = 0; i < closureSize; i++) { 1275 PetscInt p = closure[2 * i]; 1276 PetscInt dof; 1277 1278 if (numFields) { 1279 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 1280 } else { 1281 PetscCall(PetscSectionGetDof(section, p, &dof)); 1282 } 1283 childOffsets[i + 1] = childOffsets[i] + dof; 1284 } 1285 parentOffsets[0] = 0; 1286 for (i = 0; i < closureSizeP; i++) { 1287 PetscInt p = closureP[2 * i]; 1288 PetscInt dof; 1289 1290 if (numFields) { 1291 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 1292 } else { 1293 PetscCall(PetscSectionGetDof(section, p, &dof)); 1294 } 1295 parentOffsets[i + 1] = parentOffsets[i] + dof; 1296 } 1297 for (i = 0; i < closureSize; i++) { 1298 PetscInt conDof, conOff, aDof, aOff, nWork; 1299 PetscInt p = closure[2 * i]; 1300 PetscInt o = closure[2 * i + 1]; 1301 const PetscInt *perm; 1302 const PetscScalar *flip; 1303 1304 if (p < conStart || p >= conEnd) continue; 1305 if (numFields) { 1306 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &conDof)); 1307 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &conOff)); 1308 } else { 1309 PetscCall(PetscSectionGetDof(cSec, p, &conDof)); 1310 PetscCall(PetscSectionGetOffset(cSec, p, &conOff)); 1311 } 1312 if (!conDof) continue; 1313 perm = (perms && perms[i]) ? perms[i][o] : NULL; 1314 flip = (flips && flips[i]) ? flips[i][o] : NULL; 1315 PetscCall(PetscSectionGetDof(aSec, p, &aDof)); 1316 PetscCall(PetscSectionGetOffset(aSec, p, &aOff)); 1317 nWork = childOffsets[i + 1] - childOffsets[i]; 1318 for (k = 0; k < aDof; k++) { 1319 PetscInt a = anchors[aOff + k]; 1320 PetscInt aSecDof, aSecOff; 1321 1322 if (numFields) { 1323 PetscCall(PetscSectionGetFieldDof(section, a, f, &aSecDof)); 1324 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aSecOff)); 1325 } else { 1326 PetscCall(PetscSectionGetDof(section, a, &aSecDof)); 1327 PetscCall(PetscSectionGetOffset(section, a, &aSecOff)); 1328 } 1329 if (!aSecDof) continue; 1330 1331 for (j = 0; j < closureSizeP; j++) { 1332 PetscInt q = closureP[2 * j]; 1333 PetscInt oq = closureP[2 * j + 1]; 1334 1335 if (q == a) { 1336 PetscInt r, s, nWorkP; 1337 const PetscInt *permP; 1338 const PetscScalar *flipP; 1339 1340 permP = (perms && perms[j]) ? perms[j][oq] : NULL; 1341 flipP = (flips && flips[j]) ? flips[j][oq] : NULL; 1342 nWorkP = parentOffsets[j + 1] - parentOffsets[j]; 1343 /* get a copy of the child-to-anchor portion of the matrix, and transpose so that rows correspond to the 1344 * child and columns correspond to the anchor: BUT the maxrix returned by MatDenseGetArrayRead() is 1345 * column-major, so transpose-transpose = do nothing */ 1346 for (r = 0; r < nWork; r++) { 1347 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] = X[fSize * (r + childOffsets[i]) + (s + parentOffsets[j])]; 1348 } 1349 for (r = 0; r < nWork; r++) workIndRow[perm ? perm[r] : r] = conOff + r; 1350 for (s = 0; s < nWorkP; s++) workIndCol[permP ? permP[s] : s] = aSecOff + s; 1351 if (flip) { 1352 for (r = 0; r < nWork; r++) { 1353 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flip[r]; 1354 } 1355 } 1356 if (flipP) { 1357 for (r = 0; r < nWork; r++) { 1358 for (s = 0; s < nWorkP; s++) scwork[r * nWorkP + s] *= flipP[s]; 1359 } 1360 } 1361 PetscCall(MatSetValues(cMat, nWork, workIndRow, nWorkP, workIndCol, scwork, INSERT_VALUES)); 1362 break; 1363 } 1364 } 1365 } 1366 } 1367 PetscCall(MatDenseRestoreArrayRead(Xmat, &X)); 1368 PetscCall(PetscFree2(childOffsets, parentOffsets)); 1369 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1370 PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSizeP, &closureP)); 1371 } 1372 PetscCall(MatDestroy(&Amat)); 1373 PetscCall(MatDestroy(&Bmat)); 1374 PetscCall(MatDestroy(&Xmat)); 1375 PetscCall(PetscFree(scwork)); 1376 PetscCall(PetscFree7(sizes, weights, pointsRef, pointsReal, work, workIndRow, workIndCol)); 1377 if (id == PETSCFV_CLASSID) PetscCall(PetscSpaceDestroy(&bspace)); 1378 } 1379 PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY)); 1380 PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY)); 1381 PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJparent)); 1382 PetscCall(ISRestoreIndices(aIS, &anchors)); 1383 1384 PetscFunctionReturn(PETSC_SUCCESS); 1385 } 1386 1387 static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) 1388 { 1389 Mat refCmat; 1390 PetscDS ds; 1391 PetscInt numFields, maxFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN; 1392 PetscScalar ***refPointFieldMats; 1393 PetscSection refConSec, refAnSec, refSection; 1394 IS refAnIS; 1395 const PetscInt *refAnchors; 1396 const PetscInt **perms; 1397 const PetscScalar **flips; 1398 1399 PetscFunctionBegin; 1400 PetscCall(DMGetDS(refTree, &ds)); 1401 PetscCall(PetscDSGetNumFields(ds, &numFields)); 1402 maxFields = PetscMax(1, numFields); 1403 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL)); 1404 PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS)); 1405 PetscCall(ISGetIndices(refAnIS, &refAnchors)); 1406 PetscCall(DMGetLocalSection(refTree, &refSection)); 1407 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 1408 PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats)); 1409 PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldN)); 1410 PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof)); 1411 PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof)); 1412 PetscCall(PetscMalloc1(maxDof, &rows)); 1413 PetscCall(PetscMalloc1(maxDof * maxAnDof, &cols)); 1414 for (p = pRefStart; p < pRefEnd; p++) { 1415 PetscInt parent, closureSize, *closure = NULL, pDof; 1416 1417 PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL)); 1418 PetscCall(PetscSectionGetDof(refConSec, p, &pDof)); 1419 if (!pDof || parent == p) continue; 1420 1421 PetscCall(PetscMalloc1(maxFields, &refPointFieldMats[p - pRefStart])); 1422 PetscCall(PetscCalloc1(maxFields, &refPointFieldN[p - pRefStart])); 1423 PetscCall(DMPlexGetTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure)); 1424 for (f = 0; f < maxFields; f++) { 1425 PetscInt cDof, cOff, numCols, r, i; 1426 1427 if (f < numFields) { 1428 PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof)); 1429 PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff)); 1430 PetscCall(PetscSectionGetFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips)); 1431 } else { 1432 PetscCall(PetscSectionGetDof(refConSec, p, &cDof)); 1433 PetscCall(PetscSectionGetOffset(refConSec, p, &cOff)); 1434 PetscCall(PetscSectionGetPointSyms(refSection, closureSize, closure, &perms, &flips)); 1435 } 1436 1437 for (r = 0; r < cDof; r++) rows[r] = cOff + r; 1438 numCols = 0; 1439 for (i = 0; i < closureSize; i++) { 1440 PetscInt q = closure[2 * i]; 1441 PetscInt aDof, aOff, j; 1442 const PetscInt *perm = perms ? perms[i] : NULL; 1443 1444 if (numFields) { 1445 PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof)); 1446 PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff)); 1447 } else { 1448 PetscCall(PetscSectionGetDof(refSection, q, &aDof)); 1449 PetscCall(PetscSectionGetOffset(refSection, q, &aOff)); 1450 } 1451 1452 for (j = 0; j < aDof; j++) cols[numCols++] = aOff + (perm ? perm[j] : j); 1453 } 1454 refPointFieldN[p - pRefStart][f] = numCols; 1455 PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f])); 1456 PetscCall(MatGetValues(refCmat, cDof, rows, numCols, cols, refPointFieldMats[p - pRefStart][f])); 1457 if (flips) { 1458 PetscInt colOff = 0; 1459 1460 for (i = 0; i < closureSize; i++) { 1461 PetscInt q = closure[2 * i]; 1462 PetscInt aDof, aOff, j; 1463 const PetscScalar *flip = flips ? flips[i] : NULL; 1464 1465 if (numFields) { 1466 PetscCall(PetscSectionGetFieldDof(refSection, q, f, &aDof)); 1467 PetscCall(PetscSectionGetFieldOffset(refSection, q, f, &aOff)); 1468 } else { 1469 PetscCall(PetscSectionGetDof(refSection, q, &aDof)); 1470 PetscCall(PetscSectionGetOffset(refSection, q, &aOff)); 1471 } 1472 if (flip) { 1473 PetscInt k; 1474 for (k = 0; k < cDof; k++) { 1475 for (j = 0; j < aDof; j++) refPointFieldMats[p - pRefStart][f][k * numCols + colOff + j] *= flip[j]; 1476 } 1477 } 1478 colOff += aDof; 1479 } 1480 } 1481 if (numFields) { 1482 PetscCall(PetscSectionRestoreFieldPointSyms(refSection, f, closureSize, closure, &perms, &flips)); 1483 } else { 1484 PetscCall(PetscSectionRestorePointSyms(refSection, closureSize, closure, &perms, &flips)); 1485 } 1486 } 1487 PetscCall(DMPlexRestoreTransitiveClosure(refTree, parent, PETSC_TRUE, &closureSize, &closure)); 1488 } 1489 *childrenMats = refPointFieldMats; 1490 *childrenN = refPointFieldN; 1491 PetscCall(ISRestoreIndices(refAnIS, &refAnchors)); 1492 PetscCall(PetscFree(rows)); 1493 PetscCall(PetscFree(cols)); 1494 PetscFunctionReturn(PETSC_SUCCESS); 1495 } 1496 1497 static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) 1498 { 1499 PetscDS ds; 1500 PetscInt **refPointFieldN; 1501 PetscScalar ***refPointFieldMats; 1502 PetscInt numFields, maxFields, pRefStart, pRefEnd, p, f; 1503 PetscSection refConSec; 1504 1505 PetscFunctionBegin; 1506 refPointFieldN = *childrenN; 1507 *childrenN = NULL; 1508 refPointFieldMats = *childrenMats; 1509 *childrenMats = NULL; 1510 PetscCall(DMGetDS(refTree, &ds)); 1511 PetscCall(PetscDSGetNumFields(ds, &numFields)); 1512 maxFields = PetscMax(1, numFields); 1513 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL)); 1514 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 1515 for (p = pRefStart; p < pRefEnd; p++) { 1516 PetscInt parent, pDof; 1517 1518 PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL)); 1519 PetscCall(PetscSectionGetDof(refConSec, p, &pDof)); 1520 if (!pDof || parent == p) continue; 1521 1522 for (f = 0; f < maxFields; f++) { 1523 PetscInt cDof; 1524 1525 if (numFields) { 1526 PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof)); 1527 } else { 1528 PetscCall(PetscSectionGetDof(refConSec, p, &cDof)); 1529 } 1530 1531 PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f])); 1532 } 1533 PetscCall(PetscFree(refPointFieldMats[p - pRefStart])); 1534 PetscCall(PetscFree(refPointFieldN[p - pRefStart])); 1535 } 1536 PetscCall(PetscFree(refPointFieldMats)); 1537 PetscCall(PetscFree(refPointFieldN)); 1538 PetscFunctionReturn(PETSC_SUCCESS); 1539 } 1540 1541 static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat) 1542 { 1543 DM refTree; 1544 PetscDS ds; 1545 Mat refCmat; 1546 PetscInt numFields, maxFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN; 1547 PetscScalar ***refPointFieldMats, *pointWork; 1548 PetscSection refConSec, refAnSec, anSec; 1549 IS refAnIS, anIS; 1550 const PetscInt *anchors; 1551 1552 PetscFunctionBegin; 1553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1554 PetscCall(DMGetDS(dm, &ds)); 1555 PetscCall(PetscDSGetNumFields(ds, &numFields)); 1556 maxFields = PetscMax(1, numFields); 1557 PetscCall(DMPlexGetReferenceTree(dm, &refTree)); 1558 PetscCall(DMCopyDisc(dm, refTree)); 1559 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, &refCmat, NULL)); 1560 PetscCall(DMPlexGetAnchors(refTree, &refAnSec, &refAnIS)); 1561 PetscCall(DMPlexGetAnchors(dm, &anSec, &anIS)); 1562 PetscCall(ISGetIndices(anIS, &anchors)); 1563 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 1564 PetscCall(PetscSectionGetChart(conSec, &conStart, &conEnd)); 1565 PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof)); 1566 PetscCall(PetscSectionGetMaxDof(refAnSec, &maxAnDof)); 1567 PetscCall(PetscMalloc1(maxDof * maxDof * maxAnDof, &pointWork)); 1568 1569 /* step 1: get submats for every constrained point in the reference tree */ 1570 PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 1571 1572 /* step 2: compute the preorder */ 1573 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1574 PetscCall(PetscMalloc2(pEnd - pStart, &perm, pEnd - pStart, &iperm)); 1575 for (p = pStart; p < pEnd; p++) { 1576 perm[p - pStart] = p; 1577 iperm[p - pStart] = p - pStart; 1578 } 1579 for (p = 0; p < pEnd - pStart;) { 1580 PetscInt point = perm[p]; 1581 PetscInt parent; 1582 1583 PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL)); 1584 if (parent == point) { 1585 p++; 1586 } else { 1587 PetscInt size, closureSize, *closure = NULL, i; 1588 1589 PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure)); 1590 for (i = 0; i < closureSize; i++) { 1591 PetscInt q = closure[2 * i]; 1592 if (iperm[q - pStart] > iperm[point - pStart]) { 1593 /* swap */ 1594 perm[p] = q; 1595 perm[iperm[q - pStart]] = point; 1596 iperm[point - pStart] = iperm[q - pStart]; 1597 iperm[q - pStart] = p; 1598 break; 1599 } 1600 } 1601 size = closureSize; 1602 PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure)); 1603 if (i == size) p++; 1604 } 1605 } 1606 1607 /* step 3: fill the constraint matrix */ 1608 /* we are going to use a preorder progressive fill strategy. Mat doesn't 1609 * allow progressive fill without assembly, so we are going to set up the 1610 * values outside of the Mat first. 1611 */ 1612 { 1613 PetscInt nRows, row, nnz; 1614 PetscBool done; 1615 PetscInt secStart, secEnd; 1616 const PetscInt *ia, *ja; 1617 PetscScalar *vals; 1618 1619 PetscCall(PetscSectionGetChart(section, &secStart, &secEnd)); 1620 PetscCall(MatGetRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done)); 1621 PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not get RowIJ of constraint matrix"); 1622 nnz = ia[nRows]; 1623 /* malloc and then zero rows right before we fill them: this way valgrind 1624 * can tell if we are doing progressive fill in the wrong order */ 1625 PetscCall(PetscMalloc1(nnz, &vals)); 1626 for (p = 0; p < pEnd - pStart; p++) { 1627 PetscInt parent, childid, closureSize, *closure = NULL; 1628 PetscInt point = perm[p], pointDof; 1629 1630 PetscCall(DMPlexGetTreeParent(dm, point, &parent, &childid)); 1631 if ((point < conStart) || (point >= conEnd) || (parent == point)) continue; 1632 PetscCall(PetscSectionGetDof(conSec, point, &pointDof)); 1633 if (!pointDof) continue; 1634 PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure)); 1635 for (f = 0; f < maxFields; f++) { 1636 PetscInt cDof, cOff, numCols, numFillCols, i, r, matOffset, offset; 1637 PetscScalar *pointMat; 1638 const PetscInt **perms; 1639 const PetscScalar **flips; 1640 1641 if (numFields) { 1642 PetscCall(PetscSectionGetFieldDof(conSec, point, f, &cDof)); 1643 PetscCall(PetscSectionGetFieldOffset(conSec, point, f, &cOff)); 1644 } else { 1645 PetscCall(PetscSectionGetDof(conSec, point, &cDof)); 1646 PetscCall(PetscSectionGetOffset(conSec, point, &cOff)); 1647 } 1648 if (!cDof) continue; 1649 if (numFields) PetscCall(PetscSectionGetFieldPointSyms(section, f, closureSize, closure, &perms, &flips)); 1650 else PetscCall(PetscSectionGetPointSyms(section, closureSize, closure, &perms, &flips)); 1651 1652 /* make sure that every row for this point is the same size */ 1653 if (PetscDefined(USE_DEBUG)) { 1654 for (r = 0; r < cDof; r++) { 1655 if (cDof > 1 && r) { 1656 PetscCheck((ia[cOff + r + 1] - ia[cOff + r]) == (ia[cOff + r] - ia[cOff + r - 1]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two point rows have different nnz: %" PetscInt_FMT " vs. %" PetscInt_FMT, (ia[cOff + r + 1] - ia[cOff + r]), (ia[cOff + r] - ia[cOff + r - 1])); 1657 } 1658 } 1659 } 1660 /* zero rows */ 1661 for (i = ia[cOff]; i < ia[cOff + cDof]; i++) vals[i] = 0.; 1662 matOffset = ia[cOff]; 1663 numFillCols = ia[cOff + 1] - matOffset; 1664 pointMat = refPointFieldMats[childid - pRefStart][f]; 1665 numCols = refPointFieldN[childid - pRefStart][f]; 1666 offset = 0; 1667 for (i = 0; i < closureSize; i++) { 1668 PetscInt q = closure[2 * i]; 1669 PetscInt aDof, aOff, j, k, qConDof, qConOff; 1670 const PetscInt *perm = perms ? perms[i] : NULL; 1671 const PetscScalar *flip = flips ? flips[i] : NULL; 1672 1673 qConDof = qConOff = 0; 1674 if (q < secStart || q >= secEnd) continue; 1675 if (numFields) { 1676 PetscCall(PetscSectionGetFieldDof(section, q, f, &aDof)); 1677 PetscCall(PetscSectionGetFieldOffset(section, q, f, &aOff)); 1678 if (q >= conStart && q < conEnd) { 1679 PetscCall(PetscSectionGetFieldDof(conSec, q, f, &qConDof)); 1680 PetscCall(PetscSectionGetFieldOffset(conSec, q, f, &qConOff)); 1681 } 1682 } else { 1683 PetscCall(PetscSectionGetDof(section, q, &aDof)); 1684 PetscCall(PetscSectionGetOffset(section, q, &aOff)); 1685 if (q >= conStart && q < conEnd) { 1686 PetscCall(PetscSectionGetDof(conSec, q, &qConDof)); 1687 PetscCall(PetscSectionGetOffset(conSec, q, &qConOff)); 1688 } 1689 } 1690 if (!aDof) continue; 1691 if (qConDof) { 1692 /* this point has anchors: its rows of the matrix should already 1693 * be filled, thanks to preordering */ 1694 /* first multiply into pointWork, then set in matrix */ 1695 PetscInt aMatOffset = ia[qConOff]; 1696 PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset; 1697 for (r = 0; r < cDof; r++) { 1698 for (j = 0; j < aNumFillCols; j++) { 1699 PetscScalar inVal = 0; 1700 for (k = 0; k < aDof; k++) { 1701 PetscInt col = perm ? perm[k] : k; 1702 1703 inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j] * (flip ? flip[col] : 1.); 1704 } 1705 pointWork[r * aNumFillCols + j] = inVal; 1706 } 1707 } 1708 /* assume that the columns are sorted, spend less time searching */ 1709 for (j = 0, k = 0; j < aNumFillCols; j++) { 1710 PetscInt col = ja[aMatOffset + j]; 1711 for (; k < numFillCols; k++) { 1712 if (ja[matOffset + k] == col) break; 1713 } 1714 PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, col); 1715 for (r = 0; r < cDof; r++) vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j]; 1716 } 1717 } else { 1718 /* find where to put this portion of pointMat into the matrix */ 1719 for (k = 0; k < numFillCols; k++) { 1720 if (ja[matOffset + k] == aOff) break; 1721 } 1722 PetscCheck(k != numFillCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No nonzero space for (%" PetscInt_FMT ", %" PetscInt_FMT ")", cOff, aOff); 1723 for (r = 0; r < cDof; r++) { 1724 for (j = 0; j < aDof; j++) { 1725 PetscInt col = perm ? perm[j] : j; 1726 1727 vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + j] * (flip ? flip[col] : 1.); 1728 } 1729 } 1730 } 1731 offset += aDof; 1732 } 1733 if (numFields) { 1734 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, closureSize, closure, &perms, &flips)); 1735 } else { 1736 PetscCall(PetscSectionRestorePointSyms(section, closureSize, closure, &perms, &flips)); 1737 } 1738 } 1739 PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure)); 1740 } 1741 for (row = 0; row < nRows; row++) PetscCall(MatSetValues(cMat, 1, &row, ia[row + 1] - ia[row], &ja[ia[row]], &vals[ia[row]], INSERT_VALUES)); 1742 PetscCall(MatRestoreRowIJ(cMat, 0, PETSC_FALSE, PETSC_FALSE, &nRows, &ia, &ja, &done)); 1743 PetscCheck(done, PetscObjectComm((PetscObject)cMat), PETSC_ERR_PLIB, "Could not restore RowIJ of constraint matrix"); 1744 PetscCall(MatAssemblyBegin(cMat, MAT_FINAL_ASSEMBLY)); 1745 PetscCall(MatAssemblyEnd(cMat, MAT_FINAL_ASSEMBLY)); 1746 PetscCall(PetscFree(vals)); 1747 } 1748 1749 /* clean up */ 1750 PetscCall(ISRestoreIndices(anIS, &anchors)); 1751 PetscCall(PetscFree2(perm, iperm)); 1752 PetscCall(PetscFree(pointWork)); 1753 PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 1754 PetscFunctionReturn(PETSC_SUCCESS); 1755 } 1756 1757 /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of 1758 * a non-conforming mesh. Local refinement comes later */ 1759 PetscErrorCode DMPlexTreeRefineCell(DM dm, PetscInt cell, DM *ncdm) 1760 { 1761 DM K; 1762 PetscMPIInt rank; 1763 PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd; 1764 PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations; 1765 PetscInt *Kembedding; 1766 PetscInt *cellClosure = NULL, nc; 1767 PetscScalar *newVertexCoords; 1768 PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset; 1769 PetscSection parentSection; 1770 1771 PetscFunctionBegin; 1772 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1773 PetscCall(DMGetDimension(dm, &dim)); 1774 PetscCall(DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm)); 1775 PetscCall(DMSetDimension(*ncdm, dim)); 1776 1777 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1778 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &parentSection)); 1779 PetscCall(DMPlexGetReferenceTree(dm, &K)); 1780 PetscCall(DMGetCoordinatesLocalSetUp(dm)); 1781 if (rank == 0) { 1782 /* compute the new charts */ 1783 PetscCall(PetscMalloc5(dim + 1, &pNewCount, dim + 1, &pNewStart, dim + 1, &pNewEnd, dim + 1, &pOldStart, dim + 1, &pOldEnd)); 1784 offset = 0; 1785 for (d = 0; d <= dim; d++) { 1786 PetscInt pOldCount, kStart, kEnd, k; 1787 1788 pNewStart[d] = offset; 1789 PetscCall(DMPlexGetHeightStratum(dm, d, &pOldStart[d], &pOldEnd[d])); 1790 PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd)); 1791 pOldCount = pOldEnd[d] - pOldStart[d]; 1792 /* adding the new points */ 1793 pNewCount[d] = pOldCount + kEnd - kStart; 1794 if (!d) { 1795 /* removing the cell */ 1796 pNewCount[d]--; 1797 } 1798 for (k = kStart; k < kEnd; k++) { 1799 PetscInt parent; 1800 PetscCall(DMPlexGetTreeParent(K, k, &parent, NULL)); 1801 if (parent == k) { 1802 /* avoid double counting points that won't actually be new */ 1803 pNewCount[d]--; 1804 } 1805 } 1806 pNewEnd[d] = pNewStart[d] + pNewCount[d]; 1807 offset = pNewEnd[d]; 1808 } 1809 PetscCheck(cell >= pOldStart[0] && cell < pOldEnd[0], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT " not in cell range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cell, pOldStart[0], pOldEnd[0]); 1810 /* get the current closure of the cell that we are removing */ 1811 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure)); 1812 1813 PetscCall(PetscMalloc1(pNewEnd[dim], &newConeSizes)); 1814 { 1815 DMPolytopeType pct, qct; 1816 PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j; 1817 1818 PetscCall(DMPlexGetChart(K, &kStart, &kEnd)); 1819 PetscCall(PetscMalloc4(kEnd - kStart, &Kembedding, kEnd - kStart, &perm, kEnd - kStart, &iperm, kEnd - kStart, &preOrient)); 1820 1821 for (k = kStart; k < kEnd; k++) { 1822 perm[k - kStart] = k; 1823 iperm[k - kStart] = k - kStart; 1824 preOrient[k - kStart] = 0; 1825 } 1826 1827 PetscCall(DMPlexGetTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK)); 1828 for (j = 1; j < closureSizeK; j++) { 1829 PetscInt parentOrientA = closureK[2 * j + 1]; 1830 PetscInt parentOrientB = cellClosure[2 * j + 1]; 1831 PetscInt p, q; 1832 1833 p = closureK[2 * j]; 1834 q = cellClosure[2 * j]; 1835 PetscCall(DMPlexGetCellType(K, p, &pct)); 1836 PetscCall(DMPlexGetCellType(dm, q, &qct)); 1837 for (d = 0; d <= dim; d++) { 1838 if (q >= pOldStart[d] && q < pOldEnd[d]) Kembedding[p] = (q - pOldStart[d]) + pNewStart[d]; 1839 } 1840 parentOrientA = DMPolytopeConvertNewOrientation_Internal(pct, parentOrientA); 1841 parentOrientB = DMPolytopeConvertNewOrientation_Internal(qct, parentOrientB); 1842 if (parentOrientA != parentOrientB) { 1843 PetscInt numChildren, i; 1844 const PetscInt *children; 1845 1846 PetscCall(DMPlexGetTreeChildren(K, p, &numChildren, &children)); 1847 for (i = 0; i < numChildren; i++) { 1848 PetscInt kPerm, oPerm; 1849 1850 k = children[i]; 1851 PetscCall(DMPlexReferenceTreeGetChildSymmetry(K, p, parentOrientA, 0, k, parentOrientB, &oPerm, &kPerm)); 1852 /* perm = what refTree position I'm in */ 1853 perm[kPerm - kStart] = k; 1854 /* iperm = who is at this position */ 1855 iperm[k - kStart] = kPerm - kStart; 1856 preOrient[kPerm - kStart] = oPerm; 1857 } 1858 } 1859 } 1860 PetscCall(DMPlexRestoreTransitiveClosure(K, 0, PETSC_TRUE, &closureSizeK, &closureK)); 1861 } 1862 PetscCall(PetscSectionSetChart(parentSection, 0, pNewEnd[dim])); 1863 offset = 0; 1864 numNewCones = 0; 1865 for (d = 0; d <= dim; d++) { 1866 PetscInt kStart, kEnd, k; 1867 PetscInt p; 1868 PetscInt size; 1869 1870 for (p = pOldStart[d]; p < pOldEnd[d]; p++) { 1871 /* skip cell 0 */ 1872 if (p == cell) continue; 1873 /* old cones to new cones */ 1874 PetscCall(DMPlexGetConeSize(dm, p, &size)); 1875 newConeSizes[offset++] = size; 1876 numNewCones += size; 1877 } 1878 1879 PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd)); 1880 for (k = kStart; k < kEnd; k++) { 1881 PetscInt kParent; 1882 1883 PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL)); 1884 if (kParent != k) { 1885 Kembedding[k] = offset; 1886 PetscCall(DMPlexGetConeSize(K, k, &size)); 1887 newConeSizes[offset++] = size; 1888 numNewCones += size; 1889 if (kParent != 0) PetscCall(PetscSectionSetDof(parentSection, Kembedding[k], 1)); 1890 } 1891 } 1892 } 1893 1894 PetscCall(PetscSectionSetUp(parentSection)); 1895 PetscCall(PetscSectionGetStorageSize(parentSection, &numPointsWithParents)); 1896 PetscCall(PetscMalloc2(numNewCones, &newCones, numNewCones, &newOrientations)); 1897 PetscCall(PetscMalloc2(numPointsWithParents, &parents, numPointsWithParents, &childIDs)); 1898 1899 /* fill new cones */ 1900 offset = 0; 1901 for (d = 0; d <= dim; d++) { 1902 PetscInt kStart, kEnd, k, l; 1903 PetscInt p; 1904 PetscInt size; 1905 const PetscInt *cone, *orientation; 1906 1907 for (p = pOldStart[d]; p < pOldEnd[d]; p++) { 1908 /* skip cell 0 */ 1909 if (p == cell) continue; 1910 /* old cones to new cones */ 1911 PetscCall(DMPlexGetConeSize(dm, p, &size)); 1912 PetscCall(DMPlexGetCone(dm, p, &cone)); 1913 PetscCall(DMPlexGetConeOrientation(dm, p, &orientation)); 1914 for (l = 0; l < size; l++) { 1915 newCones[offset] = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1]; 1916 newOrientations[offset++] = orientation[l]; 1917 } 1918 } 1919 1920 PetscCall(DMPlexGetHeightStratum(K, d, &kStart, &kEnd)); 1921 for (k = kStart; k < kEnd; k++) { 1922 PetscInt kPerm = perm[k], kParent; 1923 PetscInt preO = preOrient[k]; 1924 1925 PetscCall(DMPlexGetTreeParent(K, k, &kParent, NULL)); 1926 if (kParent != k) { 1927 /* embed new cones */ 1928 PetscCall(DMPlexGetConeSize(K, k, &size)); 1929 PetscCall(DMPlexGetCone(K, kPerm, &cone)); 1930 PetscCall(DMPlexGetConeOrientation(K, kPerm, &orientation)); 1931 for (l = 0; l < size; l++) { 1932 PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size - (preO + 1) - l) % size); 1933 PetscInt newO, lSize, oTrue; 1934 DMPolytopeType ct = DM_NUM_POLYTOPES; 1935 1936 q = iperm[cone[m]]; 1937 newCones[offset] = Kembedding[q]; 1938 PetscCall(DMPlexGetConeSize(K, q, &lSize)); 1939 if (lSize == 2) ct = DM_POLYTOPE_SEGMENT; 1940 else if (lSize == 4) ct = DM_POLYTOPE_QUADRILATERAL; 1941 oTrue = DMPolytopeConvertNewOrientation_Internal(ct, orientation[m]); 1942 oTrue = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2); 1943 newO = DihedralCompose(lSize, oTrue, preOrient[q]); 1944 newOrientations[offset++] = DMPolytopeConvertOldOrientation_Internal(ct, newO); 1945 } 1946 if (kParent != 0) { 1947 PetscInt newPoint = Kembedding[kParent]; 1948 PetscCall(PetscSectionGetOffset(parentSection, Kembedding[k], &pOffset)); 1949 parents[pOffset] = newPoint; 1950 childIDs[pOffset] = k; 1951 } 1952 } 1953 } 1954 } 1955 1956 PetscCall(PetscMalloc1(dim * (pNewEnd[dim] - pNewStart[dim]), &newVertexCoords)); 1957 1958 /* fill coordinates */ 1959 offset = 0; 1960 { 1961 PetscInt kStart, kEnd, l; 1962 PetscSection vSection; 1963 PetscInt v; 1964 Vec coords; 1965 PetscScalar *coordvals; 1966 PetscInt dof, off; 1967 PetscReal v0[3], J[9], detJ; 1968 1969 if (PetscDefined(USE_DEBUG)) { 1970 PetscInt k; 1971 PetscCall(DMPlexGetHeightStratum(K, 0, &kStart, &kEnd)); 1972 for (k = kStart; k < kEnd; k++) { 1973 PetscCall(DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ)); 1974 PetscCheck(detJ > 0., PETSC_COMM_SELF, PETSC_ERR_PLIB, "reference tree cell %" PetscInt_FMT " has bad determinant", k); 1975 } 1976 } 1977 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ)); 1978 PetscCall(DMGetCoordinateSection(dm, &vSection)); 1979 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 1980 PetscCall(VecGetArray(coords, &coordvals)); 1981 for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) { 1982 PetscCall(PetscSectionGetDof(vSection, v, &dof)); 1983 PetscCall(PetscSectionGetOffset(vSection, v, &off)); 1984 for (l = 0; l < dof; l++) newVertexCoords[offset++] = coordvals[off + l]; 1985 } 1986 PetscCall(VecRestoreArray(coords, &coordvals)); 1987 1988 PetscCall(DMGetCoordinateSection(K, &vSection)); 1989 PetscCall(DMGetCoordinatesLocal(K, &coords)); 1990 PetscCall(VecGetArray(coords, &coordvals)); 1991 PetscCall(DMPlexGetDepthStratum(K, 0, &kStart, &kEnd)); 1992 for (v = kStart; v < kEnd; v++) { 1993 PetscReal coord[3], newCoord[3]; 1994 PetscInt vPerm = perm[v]; 1995 PetscInt kParent; 1996 const PetscReal xi0[3] = {-1., -1., -1.}; 1997 1998 PetscCall(DMPlexGetTreeParent(K, v, &kParent, NULL)); 1999 if (kParent != v) { 2000 /* this is a new vertex */ 2001 PetscCall(PetscSectionGetOffset(vSection, vPerm, &off)); 2002 for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off + l]); 2003 CoordinatesRefToReal(dim, dim, xi0, v0, J, coord, newCoord); 2004 for (l = 0; l < dim; ++l) newVertexCoords[offset + l] = newCoord[l]; 2005 offset += dim; 2006 } 2007 } 2008 PetscCall(VecRestoreArray(coords, &coordvals)); 2009 } 2010 2011 /* need to reverse the order of pNewCount: vertices first, cells last */ 2012 for (d = 0; d < (dim + 1) / 2; d++) { 2013 PetscInt tmp; 2014 2015 tmp = pNewCount[d]; 2016 pNewCount[d] = pNewCount[dim - d]; 2017 pNewCount[dim - d] = tmp; 2018 } 2019 2020 PetscCall(DMPlexCreateFromDAG(*ncdm, dim, pNewCount, newConeSizes, newCones, newOrientations, newVertexCoords)); 2021 PetscCall(DMPlexSetReferenceTree(*ncdm, K)); 2022 PetscCall(DMPlexSetTree(*ncdm, parentSection, parents, childIDs)); 2023 2024 /* clean up */ 2025 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &nc, &cellClosure)); 2026 PetscCall(PetscFree5(pNewCount, pNewStart, pNewEnd, pOldStart, pOldEnd)); 2027 PetscCall(PetscFree(newConeSizes)); 2028 PetscCall(PetscFree2(newCones, newOrientations)); 2029 PetscCall(PetscFree(newVertexCoords)); 2030 PetscCall(PetscFree2(parents, childIDs)); 2031 PetscCall(PetscFree4(Kembedding, perm, iperm, preOrient)); 2032 } else { 2033 PetscInt p, counts[4]; 2034 PetscInt *coneSizes, *cones, *orientations; 2035 Vec coordVec; 2036 PetscScalar *coords; 2037 2038 for (d = 0; d <= dim; d++) { 2039 PetscInt dStart, dEnd; 2040 2041 PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd)); 2042 counts[d] = dEnd - dStart; 2043 } 2044 PetscCall(PetscMalloc1(pEnd - pStart, &coneSizes)); 2045 for (p = pStart; p < pEnd; p++) PetscCall(DMPlexGetConeSize(dm, p, &coneSizes[p - pStart])); 2046 PetscCall(DMPlexGetCones(dm, &cones)); 2047 PetscCall(DMPlexGetConeOrientations(dm, &orientations)); 2048 PetscCall(DMGetCoordinatesLocal(dm, &coordVec)); 2049 PetscCall(VecGetArray(coordVec, &coords)); 2050 2051 PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd)); 2052 PetscCall(PetscSectionSetUp(parentSection)); 2053 PetscCall(DMPlexCreateFromDAG(*ncdm, dim, counts, coneSizes, cones, orientations, NULL)); 2054 PetscCall(DMPlexSetReferenceTree(*ncdm, K)); 2055 PetscCall(DMPlexSetTree(*ncdm, parentSection, NULL, NULL)); 2056 PetscCall(VecRestoreArray(coordVec, &coords)); 2057 } 2058 PetscCall(PetscSectionDestroy(&parentSection)); 2059 2060 PetscFunctionReturn(PETSC_SUCCESS); 2061 } 2062 2063 PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) 2064 { 2065 PetscSF coarseToFineEmbedded; 2066 PetscSection globalCoarse, globalFine; 2067 PetscSection localCoarse, localFine; 2068 PetscSection aSec, cSec; 2069 PetscSection rootIndicesSec, rootMatricesSec; 2070 PetscSection leafIndicesSec, leafMatricesSec; 2071 PetscInt *rootIndices, *leafIndices; 2072 PetscScalar *rootMatrices, *leafMatrices; 2073 IS aIS; 2074 const PetscInt *anchors; 2075 Mat cMat; 2076 PetscInt numFields, maxFields; 2077 PetscInt pStartC, pEndC, pStartF, pEndF, p; 2078 PetscInt aStart, aEnd, cStart, cEnd; 2079 PetscInt *maxChildIds; 2080 PetscInt *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO; 2081 const PetscInt ***perms; 2082 const PetscScalar ***flips; 2083 2084 PetscFunctionBegin; 2085 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 2086 PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF)); 2087 PetscCall(DMGetGlobalSection(fine, &globalFine)); 2088 { /* winnow fine points that don't have global dofs out of the sf */ 2089 PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, nleaves, l; 2090 const PetscInt *leaves; 2091 2092 PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL)); 2093 for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) { 2094 p = leaves ? leaves[l] : l; 2095 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 2096 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 2097 if ((dof - cdof) > 0) numPointsWithDofs++; 2098 } 2099 PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs)); 2100 for (l = 0, offset = 0; l < nleaves; l++) { 2101 p = leaves ? leaves[l] : l; 2102 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 2103 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 2104 if ((dof - cdof) > 0) pointsWithDofs[offset++] = l; 2105 } 2106 PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded)); 2107 PetscCall(PetscFree(pointsWithDofs)); 2108 } 2109 /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */ 2110 PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds)); 2111 for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2; 2112 PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX)); 2113 PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, childIds, maxChildIds, MPI_MAX)); 2114 2115 PetscCall(DMGetLocalSection(coarse, &localCoarse)); 2116 PetscCall(DMGetGlobalSection(coarse, &globalCoarse)); 2117 2118 PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS)); 2119 PetscCall(ISGetIndices(aIS, &anchors)); 2120 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 2121 2122 PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL)); 2123 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 2124 2125 /* create sections that will send to children the indices and matrices they will need to construct the interpolator */ 2126 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec)); 2127 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootMatricesSec)); 2128 PetscCall(PetscSectionSetChart(rootIndicesSec, pStartC, pEndC)); 2129 PetscCall(PetscSectionSetChart(rootMatricesSec, pStartC, pEndC)); 2130 PetscCall(PetscSectionGetNumFields(localCoarse, &numFields)); 2131 maxFields = PetscMax(1, numFields); 2132 PetscCall(PetscMalloc7(maxFields + 1, &offsets, maxFields + 1, &offsetsCopy, maxFields + 1, &newOffsets, maxFields + 1, &newOffsetsCopy, maxFields + 1, &rowOffsets, maxFields + 1, &numD, maxFields + 1, &numO)); 2133 PetscCall(PetscMalloc2(maxFields + 1, (PetscInt ****)&perms, maxFields + 1, (PetscScalar ****)&flips)); 2134 PetscCall(PetscMemzero((void *)perms, (maxFields + 1) * sizeof(const PetscInt **))); 2135 PetscCall(PetscMemzero((void *)flips, (maxFields + 1) * sizeof(const PetscScalar **))); 2136 2137 for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */ 2138 PetscInt dof, matSize = 0; 2139 PetscInt aDof = 0; 2140 PetscInt cDof = 0; 2141 PetscInt maxChildId = maxChildIds[p - pStartC]; 2142 PetscInt numRowIndices = 0; 2143 PetscInt numColIndices = 0; 2144 PetscInt f; 2145 2146 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 2147 if (dof < 0) dof = -(dof + 1); 2148 if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof)); 2149 if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(cSec, p, &cDof)); 2150 for (f = 0; f <= numFields; f++) offsets[f] = 0; 2151 for (f = 0; f <= numFields; f++) newOffsets[f] = 0; 2152 if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */ 2153 PetscInt *closure = NULL, closureSize, cl; 2154 2155 PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 2156 for (cl = 0; cl < closureSize; cl++) { /* get the closure */ 2157 PetscInt c = closure[2 * cl], clDof; 2158 2159 PetscCall(PetscSectionGetDof(localCoarse, c, &clDof)); 2160 numRowIndices += clDof; 2161 for (f = 0; f < numFields; f++) { 2162 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &clDof)); 2163 offsets[f + 1] += clDof; 2164 } 2165 } 2166 for (f = 0; f < numFields; f++) { 2167 offsets[f + 1] += offsets[f]; 2168 newOffsets[f + 1] = offsets[f + 1]; 2169 } 2170 /* get the number of indices needed and their field offsets */ 2171 PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, NULL, NULL, NULL, &numColIndices, NULL, NULL, newOffsets, PETSC_FALSE)); 2172 PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 2173 if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */ 2174 numColIndices = numRowIndices; 2175 matSize = 0; 2176 } else if (numFields) { /* we send one submat for each field: sum their sizes */ 2177 matSize = 0; 2178 for (f = 0; f < numFields; f++) { 2179 PetscInt numRow, numCol; 2180 2181 numRow = offsets[f + 1] - offsets[f]; 2182 numCol = newOffsets[f + 1] - newOffsets[f]; 2183 matSize += numRow * numCol; 2184 } 2185 } else { 2186 matSize = numRowIndices * numColIndices; 2187 } 2188 } else if (maxChildId == -1) { 2189 if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */ 2190 PetscInt aOff, a; 2191 2192 PetscCall(PetscSectionGetOffset(aSec, p, &aOff)); 2193 for (f = 0; f < numFields; f++) { 2194 PetscInt fDof; 2195 2196 PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof)); 2197 offsets[f + 1] = fDof; 2198 } 2199 for (a = 0; a < aDof; a++) { 2200 PetscInt anchor = anchors[a + aOff], aLocalDof; 2201 2202 PetscCall(PetscSectionGetDof(localCoarse, anchor, &aLocalDof)); 2203 numColIndices += aLocalDof; 2204 for (f = 0; f < numFields; f++) { 2205 PetscInt fDof; 2206 2207 PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof)); 2208 newOffsets[f + 1] += fDof; 2209 } 2210 } 2211 if (numFields) { 2212 matSize = 0; 2213 for (f = 0; f < numFields; f++) matSize += offsets[f + 1] * newOffsets[f + 1]; 2214 } else { 2215 matSize = numColIndices * dof; 2216 } 2217 } else { /* no children, and no constraints on dofs: just get the global indices */ 2218 numColIndices = dof; 2219 matSize = 0; 2220 } 2221 } 2222 /* we will pack the column indices with the field offsets */ 2223 PetscCall(PetscSectionSetDof(rootIndicesSec, p, numColIndices ? numColIndices + 2 * numFields : 0)); 2224 PetscCall(PetscSectionSetDof(rootMatricesSec, p, matSize)); 2225 } 2226 PetscCall(PetscSectionSetUp(rootIndicesSec)); 2227 PetscCall(PetscSectionSetUp(rootMatricesSec)); 2228 { 2229 PetscInt numRootIndices, numRootMatrices; 2230 2231 PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices)); 2232 PetscCall(PetscSectionGetStorageSize(rootMatricesSec, &numRootMatrices)); 2233 PetscCall(PetscMalloc2(numRootIndices, &rootIndices, numRootMatrices, &rootMatrices)); 2234 for (p = pStartC; p < pEndC; p++) { 2235 PetscInt numRowIndices, numColIndices, matSize, dof; 2236 PetscInt pIndOff, pMatOff, f; 2237 PetscInt *pInd; 2238 PetscInt maxChildId = maxChildIds[p - pStartC]; 2239 PetscScalar *pMat = NULL; 2240 2241 PetscCall(PetscSectionGetDof(rootIndicesSec, p, &numColIndices)); 2242 if (!numColIndices) continue; 2243 for (f = 0; f <= numFields; f++) { 2244 offsets[f] = 0; 2245 newOffsets[f] = 0; 2246 offsetsCopy[f] = 0; 2247 newOffsetsCopy[f] = 0; 2248 } 2249 numColIndices -= 2 * numFields; 2250 PetscCall(PetscSectionGetOffset(rootIndicesSec, p, &pIndOff)); 2251 pInd = &(rootIndices[pIndOff]); 2252 PetscCall(PetscSectionGetDof(rootMatricesSec, p, &matSize)); 2253 if (matSize) { 2254 PetscCall(PetscSectionGetOffset(rootMatricesSec, p, &pMatOff)); 2255 pMat = &rootMatrices[pMatOff]; 2256 } 2257 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 2258 if (dof < 0) dof = -(dof + 1); 2259 if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */ 2260 PetscInt i, j; 2261 PetscInt numRowIndices = matSize / numColIndices; 2262 2263 if (!numRowIndices) { /* don't need to calculate the mat, just the indices */ 2264 PetscInt numIndices, *indices; 2265 PetscCall(DMPlexGetClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL)); 2266 PetscCheck(numIndices == numColIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "mismatching constraint indices calculations"); 2267 for (i = 0; i < numColIndices; i++) pInd[i] = indices[i]; 2268 for (i = 0; i < numFields; i++) { 2269 pInd[numColIndices + i] = offsets[i + 1]; 2270 pInd[numColIndices + numFields + i] = offsets[i + 1]; 2271 } 2272 PetscCall(DMPlexRestoreClosureIndices(coarse, localCoarse, globalCoarse, p, PETSC_TRUE, &numIndices, &indices, offsets, NULL)); 2273 } else { 2274 PetscInt closureSize, *closure = NULL, cl; 2275 PetscScalar *pMatIn, *pMatModified; 2276 PetscInt numPoints, *points; 2277 2278 PetscCall(DMGetWorkArray(coarse, numRowIndices * numRowIndices, MPIU_SCALAR, &pMatIn)); 2279 for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */ 2280 for (j = 0; j < numRowIndices; j++) pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.; 2281 } 2282 PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 2283 for (f = 0; f < maxFields; f++) { 2284 if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f])); 2285 else PetscCall(PetscSectionGetPointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f])); 2286 } 2287 if (numFields) { 2288 for (cl = 0; cl < closureSize; cl++) { 2289 PetscInt c = closure[2 * cl]; 2290 2291 for (f = 0; f < numFields; f++) { 2292 PetscInt fDof; 2293 2294 PetscCall(PetscSectionGetFieldDof(localCoarse, c, f, &fDof)); 2295 offsets[f + 1] += fDof; 2296 } 2297 } 2298 for (f = 0; f < numFields; f++) { 2299 offsets[f + 1] += offsets[f]; 2300 newOffsets[f + 1] = offsets[f + 1]; 2301 } 2302 } 2303 /* TODO : flips here ? */ 2304 /* apply hanging node constraints on the right, get the new points and the new offsets */ 2305 PetscCall(DMPlexAnchorsModifyMat(coarse, localCoarse, closureSize, numRowIndices, closure, perms, pMatIn, &numPoints, NULL, &points, &pMatModified, newOffsets, PETSC_FALSE)); 2306 for (f = 0; f < maxFields; f++) { 2307 if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, closureSize, closure, &perms[f], &flips[f])); 2308 else PetscCall(PetscSectionRestorePointSyms(localCoarse, closureSize, closure, &perms[f], &flips[f])); 2309 } 2310 for (f = 0; f < maxFields; f++) { 2311 if (numFields) PetscCall(PetscSectionGetFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f])); 2312 else PetscCall(PetscSectionGetPointSyms(localCoarse, numPoints, points, &perms[f], &flips[f])); 2313 } 2314 if (!numFields) { 2315 for (i = 0; i < numRowIndices * numColIndices; i++) pMat[i] = pMatModified[i]; 2316 } else { 2317 PetscInt i, j, count; 2318 for (f = 0, count = 0; f < numFields; f++) { 2319 for (i = offsets[f]; i < offsets[f + 1]; i++) { 2320 for (j = newOffsets[f]; j < newOffsets[f + 1]; j++, count++) pMat[count] = pMatModified[i * numColIndices + j]; 2321 } 2322 } 2323 } 2324 PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatModified)); 2325 PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 2326 PetscCall(DMRestoreWorkArray(coarse, numRowIndices * numColIndices, MPIU_SCALAR, &pMatIn)); 2327 if (numFields) { 2328 for (f = 0; f < numFields; f++) { 2329 pInd[numColIndices + f] = offsets[f + 1]; 2330 pInd[numColIndices + numFields + f] = newOffsets[f + 1]; 2331 } 2332 for (cl = 0; cl < numPoints; cl++) { 2333 PetscInt globalOff, c = points[2 * cl]; 2334 PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff)); 2335 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perms, cl, NULL, pInd)); 2336 } 2337 } else { 2338 for (cl = 0; cl < numPoints; cl++) { 2339 PetscInt c = points[2 * cl], globalOff; 2340 const PetscInt *perm = perms[0] ? perms[0][cl] : NULL; 2341 2342 PetscCall(PetscSectionGetOffset(globalCoarse, c, &globalOff)); 2343 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, c, globalOff < 0 ? -(globalOff + 1) : globalOff, newOffsets, PETSC_FALSE, perm, NULL, pInd)); 2344 } 2345 } 2346 for (f = 0; f < maxFields; f++) { 2347 if (numFields) PetscCall(PetscSectionRestoreFieldPointSyms(localCoarse, f, numPoints, points, &perms[f], &flips[f])); 2348 else PetscCall(PetscSectionRestorePointSyms(localCoarse, numPoints, points, &perms[f], &flips[f])); 2349 } 2350 PetscCall(DMRestoreWorkArray(coarse, numPoints, MPIU_SCALAR, &points)); 2351 } 2352 } else if (matSize) { 2353 PetscInt cOff; 2354 PetscInt *rowIndices, *colIndices, a, aDof, aOff; 2355 2356 numRowIndices = matSize / numColIndices; 2357 PetscCheck(numRowIndices == dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Miscounted dofs"); 2358 PetscCall(DMGetWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices)); 2359 PetscCall(DMGetWorkArray(coarse, numColIndices, MPIU_INT, &colIndices)); 2360 PetscCall(PetscSectionGetOffset(cSec, p, &cOff)); 2361 PetscCall(PetscSectionGetDof(aSec, p, &aDof)); 2362 PetscCall(PetscSectionGetOffset(aSec, p, &aOff)); 2363 if (numFields) { 2364 for (f = 0; f < numFields; f++) { 2365 PetscInt fDof; 2366 2367 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &fDof)); 2368 offsets[f + 1] = fDof; 2369 for (a = 0; a < aDof; a++) { 2370 PetscInt anchor = anchors[a + aOff]; 2371 PetscCall(PetscSectionGetFieldDof(localCoarse, anchor, f, &fDof)); 2372 newOffsets[f + 1] += fDof; 2373 } 2374 } 2375 for (f = 0; f < numFields; f++) { 2376 offsets[f + 1] += offsets[f]; 2377 offsetsCopy[f + 1] = offsets[f + 1]; 2378 newOffsets[f + 1] += newOffsets[f]; 2379 newOffsetsCopy[f + 1] = newOffsets[f + 1]; 2380 } 2381 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, -1, NULL, rowIndices)); 2382 for (a = 0; a < aDof; a++) { 2383 PetscInt anchor = anchors[a + aOff], lOff; 2384 PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff)); 2385 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, -1, NULL, colIndices)); 2386 } 2387 } else { 2388 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, p, cOff, offsetsCopy, PETSC_TRUE, NULL, NULL, rowIndices)); 2389 for (a = 0; a < aDof; a++) { 2390 PetscInt anchor = anchors[a + aOff], lOff; 2391 PetscCall(PetscSectionGetOffset(localCoarse, anchor, &lOff)); 2392 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_TRUE, anchor, lOff, newOffsetsCopy, PETSC_TRUE, NULL, NULL, colIndices)); 2393 } 2394 } 2395 if (numFields) { 2396 PetscInt count, a; 2397 2398 for (f = 0, count = 0; f < numFields; f++) { 2399 PetscInt iSize = offsets[f + 1] - offsets[f]; 2400 PetscInt jSize = newOffsets[f + 1] - newOffsets[f]; 2401 PetscCall(MatGetValues(cMat, iSize, &rowIndices[offsets[f]], jSize, &colIndices[newOffsets[f]], &pMat[count])); 2402 count += iSize * jSize; 2403 pInd[numColIndices + f] = offsets[f + 1]; 2404 pInd[numColIndices + numFields + f] = newOffsets[f + 1]; 2405 } 2406 for (a = 0; a < aDof; a++) { 2407 PetscInt anchor = anchors[a + aOff]; 2408 PetscInt gOff; 2409 PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff)); 2410 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, -1, NULL, pInd)); 2411 } 2412 } else { 2413 PetscInt a; 2414 PetscCall(MatGetValues(cMat, numRowIndices, rowIndices, numColIndices, colIndices, pMat)); 2415 for (a = 0; a < aDof; a++) { 2416 PetscInt anchor = anchors[a + aOff]; 2417 PetscInt gOff; 2418 PetscCall(PetscSectionGetOffset(globalCoarse, anchor, &gOff)); 2419 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, anchor, gOff < 0 ? -(gOff + 1) : gOff, newOffsets, PETSC_FALSE, NULL, NULL, pInd)); 2420 } 2421 } 2422 PetscCall(DMRestoreWorkArray(coarse, numColIndices, MPIU_INT, &colIndices)); 2423 PetscCall(DMRestoreWorkArray(coarse, numRowIndices, MPIU_INT, &rowIndices)); 2424 } else { 2425 PetscInt gOff; 2426 2427 PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff)); 2428 if (numFields) { 2429 for (f = 0; f < numFields; f++) { 2430 PetscInt fDof; 2431 PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof)); 2432 offsets[f + 1] = fDof + offsets[f]; 2433 } 2434 for (f = 0; f < numFields; f++) { 2435 pInd[numColIndices + f] = offsets[f + 1]; 2436 pInd[numColIndices + numFields + f] = offsets[f + 1]; 2437 } 2438 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd)); 2439 } else { 2440 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd)); 2441 } 2442 } 2443 } 2444 PetscCall(PetscFree(maxChildIds)); 2445 } 2446 { 2447 PetscSF indicesSF, matricesSF; 2448 PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices; 2449 2450 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec)); 2451 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafMatricesSec)); 2452 PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootIndicesSec, &remoteOffsetsIndices, leafIndicesSec)); 2453 PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootMatricesSec, &remoteOffsetsMatrices, leafMatricesSec)); 2454 PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootIndicesSec, remoteOffsetsIndices, leafIndicesSec, &indicesSF)); 2455 PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootMatricesSec, remoteOffsetsMatrices, leafMatricesSec, &matricesSF)); 2456 PetscCall(PetscSFDestroy(&coarseToFineEmbedded)); 2457 PetscCall(PetscFree(remoteOffsetsIndices)); 2458 PetscCall(PetscFree(remoteOffsetsMatrices)); 2459 PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numLeafIndices)); 2460 PetscCall(PetscSectionGetStorageSize(leafMatricesSec, &numLeafMatrices)); 2461 PetscCall(PetscMalloc2(numLeafIndices, &leafIndices, numLeafMatrices, &leafMatrices)); 2462 PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE)); 2463 PetscCall(PetscSFBcastBegin(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE)); 2464 PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, rootIndices, leafIndices, MPI_REPLACE)); 2465 PetscCall(PetscSFBcastEnd(matricesSF, MPIU_SCALAR, rootMatrices, leafMatrices, MPI_REPLACE)); 2466 PetscCall(PetscSFDestroy(&matricesSF)); 2467 PetscCall(PetscSFDestroy(&indicesSF)); 2468 PetscCall(PetscFree2(rootIndices, rootMatrices)); 2469 PetscCall(PetscSectionDestroy(&rootIndicesSec)); 2470 PetscCall(PetscSectionDestroy(&rootMatricesSec)); 2471 } 2472 /* count to preallocate */ 2473 PetscCall(DMGetLocalSection(fine, &localFine)); 2474 { 2475 PetscInt nGlobal; 2476 PetscInt *dnnz, *onnz; 2477 PetscLayout rowMap, colMap; 2478 PetscInt rowStart, rowEnd, colStart, colEnd; 2479 PetscInt maxDof; 2480 PetscInt *rowIndices; 2481 DM refTree; 2482 PetscInt **refPointFieldN; 2483 PetscScalar ***refPointFieldMats; 2484 PetscSection refConSec, refAnSec; 2485 PetscInt pRefStart, pRefEnd, maxConDof, maxColumns, leafStart, leafEnd; 2486 PetscScalar *pointWork; 2487 2488 PetscCall(PetscSectionGetConstrainedStorageSize(globalFine, &nGlobal)); 2489 PetscCall(PetscCalloc2(nGlobal, &dnnz, nGlobal, &onnz)); 2490 PetscCall(MatGetLayouts(mat, &rowMap, &colMap)); 2491 PetscCall(PetscLayoutSetUp(rowMap)); 2492 PetscCall(PetscLayoutSetUp(colMap)); 2493 PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd)); 2494 PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd)); 2495 PetscCall(PetscSectionGetMaxDof(localFine, &maxDof)); 2496 PetscCall(PetscSectionGetChart(leafIndicesSec, &leafStart, &leafEnd)); 2497 PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices)); 2498 for (p = leafStart; p < leafEnd; p++) { 2499 PetscInt gDof, gcDof, gOff; 2500 PetscInt numColIndices, pIndOff, *pInd; 2501 PetscInt matSize; 2502 PetscInt i; 2503 2504 PetscCall(PetscSectionGetDof(globalFine, p, &gDof)); 2505 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof)); 2506 if ((gDof - gcDof) <= 0) continue; 2507 PetscCall(PetscSectionGetOffset(globalFine, p, &gOff)); 2508 PetscCheck(gOff >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I though having global dofs meant a non-negative offset"); 2509 PetscCheck(gOff >= rowStart && (gOff + gDof - gcDof) <= rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "I thought the row map would constrain the global dofs"); 2510 PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices)); 2511 PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff)); 2512 numColIndices -= 2 * numFields; 2513 PetscCheck(numColIndices > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "global fine dof with no dofs to interpolate from"); 2514 pInd = &leafIndices[pIndOff]; 2515 offsets[0] = 0; 2516 offsetsCopy[0] = 0; 2517 newOffsets[0] = 0; 2518 newOffsetsCopy[0] = 0; 2519 if (numFields) { 2520 PetscInt f; 2521 for (f = 0; f < numFields; f++) { 2522 PetscInt rowDof; 2523 2524 PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof)); 2525 offsets[f + 1] = offsets[f] + rowDof; 2526 offsetsCopy[f + 1] = offsets[f + 1]; 2527 newOffsets[f + 1] = pInd[numColIndices + numFields + f]; 2528 numD[f] = 0; 2529 numO[f] = 0; 2530 } 2531 PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices)); 2532 for (f = 0; f < numFields; f++) { 2533 PetscInt colOffset = newOffsets[f]; 2534 PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f]; 2535 2536 for (i = 0; i < numFieldCols; i++) { 2537 PetscInt gInd = pInd[i + colOffset]; 2538 2539 if (gInd >= colStart && gInd < colEnd) { 2540 numD[f]++; 2541 } else if (gInd >= 0) { /* negative means non-entry */ 2542 numO[f]++; 2543 } 2544 } 2545 } 2546 } else { 2547 PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices)); 2548 numD[0] = 0; 2549 numO[0] = 0; 2550 for (i = 0; i < numColIndices; i++) { 2551 PetscInt gInd = pInd[i]; 2552 2553 if (gInd >= colStart && gInd < colEnd) { 2554 numD[0]++; 2555 } else if (gInd >= 0) { /* negative means non-entry */ 2556 numO[0]++; 2557 } 2558 } 2559 } 2560 PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize)); 2561 if (!matSize) { /* incoming matrix is identity */ 2562 PetscInt childId; 2563 2564 childId = childIds[p - pStartF]; 2565 if (childId < 0) { /* no child interpolation: one nnz per */ 2566 if (numFields) { 2567 PetscInt f; 2568 for (f = 0; f < numFields; f++) { 2569 PetscInt numRows = offsets[f + 1] - offsets[f], row; 2570 for (row = 0; row < numRows; row++) { 2571 PetscInt gIndCoarse = pInd[newOffsets[f] + row]; 2572 PetscInt gIndFine = rowIndices[offsets[f] + row]; 2573 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */ 2574 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2575 dnnz[gIndFine - rowStart] = 1; 2576 } else if (gIndCoarse >= 0) { /* remote */ 2577 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2578 onnz[gIndFine - rowStart] = 1; 2579 } else { /* constrained */ 2580 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2581 } 2582 } 2583 } 2584 } else { 2585 PetscInt i; 2586 for (i = 0; i < gDof; i++) { 2587 PetscInt gIndCoarse = pInd[i]; 2588 PetscInt gIndFine = rowIndices[i]; 2589 if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */ 2590 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2591 dnnz[gIndFine - rowStart] = 1; 2592 } else if (gIndCoarse >= 0) { /* remote */ 2593 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2594 onnz[gIndFine - rowStart] = 1; 2595 } else { /* constrained */ 2596 PetscCheck(gIndFine < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2597 } 2598 } 2599 } 2600 } else { /* interpolate from all */ 2601 if (numFields) { 2602 PetscInt f; 2603 for (f = 0; f < numFields; f++) { 2604 PetscInt numRows = offsets[f + 1] - offsets[f], row; 2605 for (row = 0; row < numRows; row++) { 2606 PetscInt gIndFine = rowIndices[offsets[f] + row]; 2607 if (gIndFine >= 0) { 2608 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2609 dnnz[gIndFine - rowStart] = numD[f]; 2610 onnz[gIndFine - rowStart] = numO[f]; 2611 } 2612 } 2613 } 2614 } else { 2615 PetscInt i; 2616 for (i = 0; i < gDof; i++) { 2617 PetscInt gIndFine = rowIndices[i]; 2618 if (gIndFine >= 0) { 2619 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2620 dnnz[gIndFine - rowStart] = numD[0]; 2621 onnz[gIndFine - rowStart] = numO[0]; 2622 } 2623 } 2624 } 2625 } 2626 } else { /* interpolate from all */ 2627 if (numFields) { 2628 PetscInt f; 2629 for (f = 0; f < numFields; f++) { 2630 PetscInt numRows = offsets[f + 1] - offsets[f], row; 2631 for (row = 0; row < numRows; row++) { 2632 PetscInt gIndFine = rowIndices[offsets[f] + row]; 2633 if (gIndFine >= 0) { 2634 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2635 dnnz[gIndFine - rowStart] = numD[f]; 2636 onnz[gIndFine - rowStart] = numO[f]; 2637 } 2638 } 2639 } 2640 } else { /* every dof get a full row */ 2641 PetscInt i; 2642 for (i = 0; i < gDof; i++) { 2643 PetscInt gIndFine = rowIndices[i]; 2644 if (gIndFine >= 0) { 2645 PetscCheck(gIndFine >= rowStart && gIndFine < rowEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatched number of constrained dofs"); 2646 dnnz[gIndFine - rowStart] = numD[0]; 2647 onnz[gIndFine - rowStart] = numO[0]; 2648 } 2649 } 2650 } 2651 } 2652 } 2653 PetscCall(MatXAIJSetPreallocation(mat, 1, dnnz, onnz, NULL, NULL)); 2654 PetscCall(PetscFree2(dnnz, onnz)); 2655 2656 PetscCall(DMPlexGetReferenceTree(fine, &refTree)); 2657 PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 2658 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL)); 2659 PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL)); 2660 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 2661 PetscCall(PetscSectionGetMaxDof(refConSec, &maxConDof)); 2662 PetscCall(PetscSectionGetMaxDof(leafIndicesSec, &maxColumns)); 2663 PetscCall(PetscMalloc1(maxConDof * maxColumns, &pointWork)); 2664 for (p = leafStart; p < leafEnd; p++) { 2665 PetscInt gDof, gcDof, gOff; 2666 PetscInt numColIndices, pIndOff, *pInd; 2667 PetscInt matSize; 2668 PetscInt childId; 2669 2670 PetscCall(PetscSectionGetDof(globalFine, p, &gDof)); 2671 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof)); 2672 if ((gDof - gcDof) <= 0) continue; 2673 childId = childIds[p - pStartF]; 2674 PetscCall(PetscSectionGetOffset(globalFine, p, &gOff)); 2675 PetscCall(PetscSectionGetDof(leafIndicesSec, p, &numColIndices)); 2676 PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &pIndOff)); 2677 numColIndices -= 2 * numFields; 2678 pInd = &leafIndices[pIndOff]; 2679 offsets[0] = 0; 2680 offsetsCopy[0] = 0; 2681 newOffsets[0] = 0; 2682 newOffsetsCopy[0] = 0; 2683 rowOffsets[0] = 0; 2684 if (numFields) { 2685 PetscInt f; 2686 for (f = 0; f < numFields; f++) { 2687 PetscInt rowDof; 2688 2689 PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof)); 2690 offsets[f + 1] = offsets[f] + rowDof; 2691 offsetsCopy[f + 1] = offsets[f + 1]; 2692 rowOffsets[f + 1] = pInd[numColIndices + f]; 2693 newOffsets[f + 1] = pInd[numColIndices + numFields + f]; 2694 } 2695 PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices)); 2696 } else { 2697 PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices)); 2698 } 2699 PetscCall(PetscSectionGetDof(leafMatricesSec, p, &matSize)); 2700 if (!matSize) { /* incoming matrix is identity */ 2701 if (childId < 0) { /* no child interpolation: scatter */ 2702 if (numFields) { 2703 PetscInt f; 2704 for (f = 0; f < numFields; f++) { 2705 PetscInt numRows = offsets[f + 1] - offsets[f], row; 2706 for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[offsets[f] + row], pInd[newOffsets[f] + row], 1., INSERT_VALUES)); 2707 } 2708 } else { 2709 PetscInt numRows = gDof, row; 2710 for (row = 0; row < numRows; row++) PetscCall(MatSetValue(mat, rowIndices[row], pInd[row], 1., INSERT_VALUES)); 2711 } 2712 } else { /* interpolate from all */ 2713 if (numFields) { 2714 PetscInt f; 2715 for (f = 0; f < numFields; f++) { 2716 PetscInt numRows = offsets[f + 1] - offsets[f]; 2717 PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; 2718 PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], refPointFieldMats[childId - pRefStart][f], INSERT_VALUES)); 2719 } 2720 } else { 2721 PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, refPointFieldMats[childId - pRefStart][0], INSERT_VALUES)); 2722 } 2723 } 2724 } else { /* interpolate from all */ 2725 PetscInt pMatOff; 2726 PetscScalar *pMat; 2727 2728 PetscCall(PetscSectionGetOffset(leafMatricesSec, p, &pMatOff)); 2729 pMat = &leafMatrices[pMatOff]; 2730 if (childId < 0) { /* copy the incoming matrix */ 2731 if (numFields) { 2732 PetscInt f, count; 2733 for (f = 0, count = 0; f < numFields; f++) { 2734 PetscInt numRows = offsets[f + 1] - offsets[f]; 2735 PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; 2736 PetscInt numInRows = rowOffsets[f + 1] - rowOffsets[f]; 2737 PetscScalar *inMat = &pMat[count]; 2738 2739 PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], inMat, INSERT_VALUES)); 2740 count += numCols * numInRows; 2741 } 2742 } else { 2743 PetscCall(MatSetValues(mat, gDof, rowIndices, numColIndices, pInd, pMat, INSERT_VALUES)); 2744 } 2745 } else { /* multiply the incoming matrix by the child interpolation */ 2746 if (numFields) { 2747 PetscInt f, count; 2748 for (f = 0, count = 0; f < numFields; f++) { 2749 PetscInt numRows = offsets[f + 1] - offsets[f]; 2750 PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; 2751 PetscInt numInRows = rowOffsets[f + 1] - rowOffsets[f]; 2752 PetscScalar *inMat = &pMat[count]; 2753 PetscInt i, j, k; 2754 PetscCheck(refPointFieldN[childId - pRefStart][f] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch"); 2755 for (i = 0; i < numRows; i++) { 2756 for (j = 0; j < numCols; j++) { 2757 PetscScalar val = 0.; 2758 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j]; 2759 pointWork[i * numCols + j] = val; 2760 } 2761 } 2762 PetscCall(MatSetValues(mat, numRows, &rowIndices[offsets[f]], numCols, &pInd[newOffsets[f]], pointWork, INSERT_VALUES)); 2763 count += numCols * numInRows; 2764 } 2765 } else { /* every dof gets a full row */ 2766 PetscInt numRows = gDof; 2767 PetscInt numCols = numColIndices; 2768 PetscInt numInRows = matSize / numColIndices; 2769 PetscInt i, j, k; 2770 PetscCheck(refPointFieldN[childId - pRefStart][0] == numInRows, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point constraint matrix multiply dimension mismatch"); 2771 for (i = 0; i < numRows; i++) { 2772 for (j = 0; j < numCols; j++) { 2773 PetscScalar val = 0.; 2774 for (k = 0; k < numInRows; k++) val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j]; 2775 pointWork[i * numCols + j] = val; 2776 } 2777 } 2778 PetscCall(MatSetValues(mat, numRows, rowIndices, numCols, pInd, pointWork, INSERT_VALUES)); 2779 } 2780 } 2781 } 2782 } 2783 PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 2784 PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices)); 2785 PetscCall(PetscFree(pointWork)); 2786 } 2787 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 2788 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 2789 PetscCall(PetscSectionDestroy(&leafIndicesSec)); 2790 PetscCall(PetscSectionDestroy(&leafMatricesSec)); 2791 PetscCall(PetscFree2(leafIndices, leafMatrices)); 2792 PetscCall(PetscFree2(*(PetscInt ****)&perms, *(PetscScalar ****)&flips)); 2793 PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO)); 2794 PetscCall(ISRestoreIndices(aIS, &anchors)); 2795 PetscFunctionReturn(PETSC_SUCCESS); 2796 } 2797 2798 /* 2799 * Assuming a nodal basis (w.r.t. the dual basis) basis: 2800 * 2801 * for each coarse dof \phi^c_i: 2802 * for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i: 2803 * for each fine dof \phi^f_j; 2804 * a_{i,j} = 0; 2805 * for each fine dof \phi^f_k: 2806 * a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l 2807 * [^^^ this is = \phi^c_i ^^^] 2808 */ 2809 PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj) 2810 { 2811 PetscDS ds; 2812 PetscSection section, cSection; 2813 DMLabel canonical, depth; 2814 Mat cMat, mat; 2815 PetscInt *nnz; 2816 PetscInt f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd; 2817 PetscInt m, n; 2818 PetscScalar *pointScalar; 2819 PetscReal *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent; 2820 2821 PetscFunctionBegin; 2822 PetscCall(DMGetLocalSection(refTree, §ion)); 2823 PetscCall(DMGetDimension(refTree, &dim)); 2824 PetscCall(PetscMalloc6(dim, &v0, dim, &v0parent, dim, &vtmp, dim * dim, &J, dim * dim, &Jparent, dim * dim, &invJ)); 2825 PetscCall(PetscMalloc2(dim, &pointScalar, dim, &pointRef)); 2826 PetscCall(DMGetDS(refTree, &ds)); 2827 PetscCall(PetscDSGetNumFields(ds, &numFields)); 2828 PetscCall(PetscSectionGetNumFields(section, &numSecFields)); 2829 PetscCall(DMGetLabel(refTree, "canonical", &canonical)); 2830 PetscCall(DMGetLabel(refTree, "depth", &depth)); 2831 PetscCall(DMGetDefaultConstraints(refTree, &cSection, &cMat, NULL)); 2832 PetscCall(DMPlexGetChart(refTree, &pStart, &pEnd)); 2833 PetscCall(DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd)); 2834 PetscCall(MatGetSize(cMat, &n, &m)); /* the injector has transpose sizes from the constraint matrix */ 2835 /* Step 1: compute non-zero pattern. A proper subset of constraint matrix non-zero */ 2836 PetscCall(PetscCalloc1(m, &nnz)); 2837 for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */ 2838 const PetscInt *children; 2839 PetscInt numChildren; 2840 PetscInt i, numChildDof, numSelfDof; 2841 2842 if (canonical) { 2843 PetscInt pCanonical; 2844 PetscCall(DMLabelGetValue(canonical, p, &pCanonical)); 2845 if (p != pCanonical) continue; 2846 } 2847 PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children)); 2848 if (!numChildren) continue; 2849 for (i = 0, numChildDof = 0; i < numChildren; i++) { 2850 PetscInt child = children[i]; 2851 PetscInt dof; 2852 2853 PetscCall(PetscSectionGetDof(section, child, &dof)); 2854 numChildDof += dof; 2855 } 2856 PetscCall(PetscSectionGetDof(section, p, &numSelfDof)); 2857 if (!numChildDof || !numSelfDof) continue; 2858 for (f = 0; f < numFields; f++) { 2859 PetscInt selfOff; 2860 2861 if (numSecFields) { /* count the dofs for just this field */ 2862 for (i = 0, numChildDof = 0; i < numChildren; i++) { 2863 PetscInt child = children[i]; 2864 PetscInt dof; 2865 2866 PetscCall(PetscSectionGetFieldDof(section, child, f, &dof)); 2867 numChildDof += dof; 2868 } 2869 PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof)); 2870 PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff)); 2871 } else { 2872 PetscCall(PetscSectionGetOffset(section, p, &selfOff)); 2873 } 2874 for (i = 0; i < numSelfDof; i++) nnz[selfOff + i] = numChildDof; 2875 } 2876 } 2877 PetscCall(MatCreateAIJ(PETSC_COMM_SELF, m, n, m, n, -1, nnz, -1, NULL, &mat)); 2878 PetscCall(PetscFree(nnz)); 2879 /* Setp 2: compute entries */ 2880 for (p = pStart; p < pEnd; p++) { 2881 const PetscInt *children; 2882 PetscInt numChildren; 2883 PetscInt i, numChildDof, numSelfDof; 2884 2885 /* same conditions about when entries occur */ 2886 if (canonical) { 2887 PetscInt pCanonical; 2888 PetscCall(DMLabelGetValue(canonical, p, &pCanonical)); 2889 if (p != pCanonical) continue; 2890 } 2891 PetscCall(DMPlexGetTreeChildren(refTree, p, &numChildren, &children)); 2892 if (!numChildren) continue; 2893 for (i = 0, numChildDof = 0; i < numChildren; i++) { 2894 PetscInt child = children[i]; 2895 PetscInt dof; 2896 2897 PetscCall(PetscSectionGetDof(section, child, &dof)); 2898 numChildDof += dof; 2899 } 2900 PetscCall(PetscSectionGetDof(section, p, &numSelfDof)); 2901 if (!numChildDof || !numSelfDof) continue; 2902 2903 for (f = 0; f < numFields; f++) { 2904 PetscInt pI = -1, cI = -1; 2905 PetscInt selfOff, Nc, parentCell; 2906 PetscInt cellShapeOff; 2907 PetscObject disc; 2908 PetscDualSpace dsp; 2909 PetscClassId classId; 2910 PetscScalar *pointMat; 2911 PetscInt *matRows, *matCols; 2912 PetscInt pO = PETSC_MIN_INT; 2913 const PetscInt *depthNumDof; 2914 2915 if (numSecFields) { 2916 for (i = 0, numChildDof = 0; i < numChildren; i++) { 2917 PetscInt child = children[i]; 2918 PetscInt dof; 2919 2920 PetscCall(PetscSectionGetFieldDof(section, child, f, &dof)); 2921 numChildDof += dof; 2922 } 2923 PetscCall(PetscSectionGetFieldDof(section, p, f, &numSelfDof)); 2924 PetscCall(PetscSectionGetFieldOffset(section, p, f, &selfOff)); 2925 } else { 2926 PetscCall(PetscSectionGetOffset(section, p, &selfOff)); 2927 } 2928 2929 /* find a cell whose closure contains p */ 2930 if (p >= cStart && p < cEnd) { 2931 parentCell = p; 2932 } else { 2933 PetscInt *star = NULL; 2934 PetscInt numStar; 2935 2936 parentCell = -1; 2937 PetscCall(DMPlexGetTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star)); 2938 for (i = numStar - 1; i >= 0; i--) { 2939 PetscInt c = star[2 * i]; 2940 2941 if (c >= cStart && c < cEnd) { 2942 parentCell = c; 2943 break; 2944 } 2945 } 2946 PetscCall(DMPlexRestoreTransitiveClosure(refTree, p, PETSC_FALSE, &numStar, &star)); 2947 } 2948 /* determine the offset of p's shape functions within parentCell's shape functions */ 2949 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 2950 PetscCall(PetscObjectGetClassId(disc, &classId)); 2951 if (classId == PETSCFE_CLASSID) { 2952 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 2953 } else if (classId == PETSCFV_CLASSID) { 2954 PetscCall(PetscFVGetDualSpace((PetscFV)disc, &dsp)); 2955 } else { 2956 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported discretization object"); 2957 } 2958 PetscCall(PetscDualSpaceGetNumDof(dsp, &depthNumDof)); 2959 PetscCall(PetscDualSpaceGetNumComponents(dsp, &Nc)); 2960 { 2961 PetscInt *closure = NULL; 2962 PetscInt numClosure; 2963 2964 PetscCall(DMPlexGetTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure)); 2965 for (i = 0, pI = -1, cellShapeOff = 0; i < numClosure; i++) { 2966 PetscInt point = closure[2 * i], pointDepth; 2967 2968 pO = closure[2 * i + 1]; 2969 if (point == p) { 2970 pI = i; 2971 break; 2972 } 2973 PetscCall(DMLabelGetValue(depth, point, &pointDepth)); 2974 cellShapeOff += depthNumDof[pointDepth]; 2975 } 2976 PetscCall(DMPlexRestoreTransitiveClosure(refTree, parentCell, PETSC_TRUE, &numClosure, &closure)); 2977 } 2978 2979 PetscCall(DMGetWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat)); 2980 PetscCall(DMGetWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows)); 2981 matCols = matRows + numSelfDof; 2982 for (i = 0; i < numSelfDof; i++) matRows[i] = selfOff + i; 2983 for (i = 0; i < numSelfDof * numChildDof; i++) pointMat[i] = 0.; 2984 { 2985 PetscInt colOff = 0; 2986 2987 for (i = 0; i < numChildren; i++) { 2988 PetscInt child = children[i]; 2989 PetscInt dof, off, j; 2990 2991 if (numSecFields) { 2992 PetscCall(PetscSectionGetFieldDof(cSection, child, f, &dof)); 2993 PetscCall(PetscSectionGetFieldOffset(cSection, child, f, &off)); 2994 } else { 2995 PetscCall(PetscSectionGetDof(cSection, child, &dof)); 2996 PetscCall(PetscSectionGetOffset(cSection, child, &off)); 2997 } 2998 2999 for (j = 0; j < dof; j++) matCols[colOff++] = off + j; 3000 } 3001 } 3002 if (classId == PETSCFE_CLASSID) { 3003 PetscFE fe = (PetscFE)disc; 3004 PetscInt fSize; 3005 const PetscInt ***perms; 3006 const PetscScalar ***flips; 3007 const PetscInt *pperms; 3008 3009 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 3010 PetscCall(PetscDualSpaceGetDimension(dsp, &fSize)); 3011 PetscCall(PetscDualSpaceGetSymmetries(dsp, &perms, &flips)); 3012 pperms = perms ? perms[pI] ? perms[pI][pO] : NULL : NULL; 3013 for (i = 0; i < numSelfDof; i++) { /* for every shape function */ 3014 PetscQuadrature q; 3015 PetscInt dim, thisNc, numPoints, j, k; 3016 const PetscReal *points; 3017 const PetscReal *weights; 3018 PetscInt *closure = NULL; 3019 PetscInt numClosure; 3020 PetscInt iCell = pperms ? pperms[i] : i; 3021 PetscInt parentCellShapeDof = cellShapeOff + iCell; 3022 PetscTabulation Tparent; 3023 3024 PetscCall(PetscDualSpaceGetFunctional(dsp, parentCellShapeDof, &q)); 3025 PetscCall(PetscQuadratureGetData(q, &dim, &thisNc, &numPoints, &points, &weights)); 3026 PetscCheck(thisNc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Functional dim %" PetscInt_FMT " does not much basis dim %" PetscInt_FMT, thisNc, Nc); 3027 PetscCall(PetscFECreateTabulation(fe, 1, numPoints, points, 0, &Tparent)); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */ 3028 for (j = 0; j < numPoints; j++) { 3029 PetscInt childCell = -1; 3030 PetscReal *parentValAtPoint; 3031 const PetscReal xi0[3] = {-1., -1., -1.}; 3032 const PetscReal *pointReal = &points[dim * j]; 3033 const PetscScalar *point; 3034 PetscTabulation Tchild; 3035 PetscInt childCellShapeOff, pointMatOff; 3036 #if defined(PETSC_USE_COMPLEX) 3037 PetscInt d; 3038 3039 for (d = 0; d < dim; d++) pointScalar[d] = points[dim * j + d]; 3040 point = pointScalar; 3041 #else 3042 point = pointReal; 3043 #endif 3044 3045 parentValAtPoint = &Tparent->T[0][(fSize * j + parentCellShapeDof) * Nc]; 3046 3047 for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/ 3048 PetscInt child = children[k]; 3049 PetscInt *star = NULL; 3050 PetscInt numStar, s; 3051 3052 PetscCall(DMPlexGetTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star)); 3053 for (s = numStar - 1; s >= 0; s--) { 3054 PetscInt c = star[2 * s]; 3055 3056 if (c < cStart || c >= cEnd) continue; 3057 PetscCall(DMPlexLocatePoint_Internal(refTree, dim, point, c, &childCell)); 3058 if (childCell >= 0) break; 3059 } 3060 PetscCall(DMPlexRestoreTransitiveClosure(refTree, child, PETSC_FALSE, &numStar, &star)); 3061 if (childCell >= 0) break; 3062 } 3063 PetscCheck(childCell >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not locate quadrature point"); 3064 PetscCall(DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ)); 3065 PetscCall(DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent)); 3066 CoordinatesRefToReal(dim, dim, xi0, v0parent, Jparent, pointReal, vtmp); 3067 CoordinatesRealToRef(dim, dim, xi0, v0, invJ, vtmp, pointRef); 3068 3069 PetscCall(PetscFECreateTabulation(fe, 1, 1, pointRef, 0, &Tchild)); 3070 PetscCall(DMPlexGetTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure)); 3071 for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */ 3072 PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT; 3073 PetscInt l; 3074 const PetscInt *cperms; 3075 3076 PetscCall(DMLabelGetValue(depth, child, &childDepth)); 3077 childDof = depthNumDof[childDepth]; 3078 for (l = 0, cI = -1, childCellShapeOff = 0; l < numClosure; l++) { 3079 PetscInt point = closure[2 * l]; 3080 PetscInt pointDepth; 3081 3082 childO = closure[2 * l + 1]; 3083 if (point == child) { 3084 cI = l; 3085 break; 3086 } 3087 PetscCall(DMLabelGetValue(depth, point, &pointDepth)); 3088 childCellShapeOff += depthNumDof[pointDepth]; 3089 } 3090 if (l == numClosure) { 3091 pointMatOff += childDof; 3092 continue; /* child is not in the closure of the cell: has nothing to contribute to this point */ 3093 } 3094 cperms = perms ? perms[cI] ? perms[cI][childO] : NULL : NULL; 3095 for (l = 0; l < childDof; l++) { 3096 PetscInt lCell = cperms ? cperms[l] : l; 3097 PetscInt childCellDof = childCellShapeOff + lCell; 3098 PetscReal *childValAtPoint; 3099 PetscReal val = 0.; 3100 3101 childValAtPoint = &Tchild->T[0][childCellDof * Nc]; 3102 for (m = 0; m < Nc; m++) val += weights[j * Nc + m] * parentValAtPoint[m] * childValAtPoint[m]; 3103 3104 pointMat[i * numChildDof + pointMatOff + l] += val; 3105 } 3106 pointMatOff += childDof; 3107 } 3108 PetscCall(DMPlexRestoreTransitiveClosure(refTree, childCell, PETSC_TRUE, &numClosure, &closure)); 3109 PetscCall(PetscTabulationDestroy(&Tchild)); 3110 } 3111 PetscCall(PetscTabulationDestroy(&Tparent)); 3112 } 3113 } else { /* just the volume-weighted averages of the children */ 3114 PetscReal parentVol; 3115 PetscInt childCell; 3116 3117 PetscCall(DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL)); 3118 for (i = 0, childCell = 0; i < numChildren; i++) { 3119 PetscInt child = children[i], j; 3120 PetscReal childVol; 3121 3122 if (child < cStart || child >= cEnd) continue; 3123 PetscCall(DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL)); 3124 for (j = 0; j < Nc; j++) pointMat[j * numChildDof + Nc * childCell + j] = childVol / parentVol; 3125 childCell++; 3126 } 3127 } 3128 /* Insert pointMat into mat */ 3129 PetscCall(MatSetValues(mat, numSelfDof, matRows, numChildDof, matCols, pointMat, INSERT_VALUES)); 3130 PetscCall(DMRestoreWorkArray(refTree, numSelfDof + numChildDof, MPIU_INT, &matRows)); 3131 PetscCall(DMRestoreWorkArray(refTree, numSelfDof * numChildDof, MPIU_SCALAR, &pointMat)); 3132 } 3133 } 3134 PetscCall(PetscFree6(v0, v0parent, vtmp, J, Jparent, invJ)); 3135 PetscCall(PetscFree2(pointScalar, pointRef)); 3136 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 3137 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 3138 *inj = mat; 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) 3143 { 3144 PetscDS ds; 3145 PetscInt numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof; 3146 PetscScalar ***refPointFieldMats; 3147 PetscSection refConSec, refSection; 3148 3149 PetscFunctionBegin; 3150 PetscCall(DMGetDS(refTree, &ds)); 3151 PetscCall(PetscDSGetNumFields(ds, &numFields)); 3152 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL)); 3153 PetscCall(DMGetLocalSection(refTree, &refSection)); 3154 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 3155 PetscCall(PetscMalloc1(pRefEnd - pRefStart, &refPointFieldMats)); 3156 PetscCall(PetscSectionGetMaxDof(refConSec, &maxDof)); 3157 PetscCall(PetscMalloc1(maxDof, &rows)); 3158 PetscCall(PetscMalloc1(maxDof * maxDof, &cols)); 3159 for (p = pRefStart; p < pRefEnd; p++) { 3160 PetscInt parent, pDof, parentDof; 3161 3162 PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL)); 3163 PetscCall(PetscSectionGetDof(refConSec, p, &pDof)); 3164 PetscCall(PetscSectionGetDof(refSection, parent, &parentDof)); 3165 if (!pDof || !parentDof || parent == p) continue; 3166 3167 PetscCall(PetscMalloc1(numFields, &refPointFieldMats[p - pRefStart])); 3168 for (f = 0; f < numFields; f++) { 3169 PetscInt cDof, cOff, numCols, r; 3170 3171 if (numFields > 1) { 3172 PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof)); 3173 PetscCall(PetscSectionGetFieldOffset(refConSec, p, f, &cOff)); 3174 } else { 3175 PetscCall(PetscSectionGetDof(refConSec, p, &cDof)); 3176 PetscCall(PetscSectionGetOffset(refConSec, p, &cOff)); 3177 } 3178 3179 for (r = 0; r < cDof; r++) rows[r] = cOff + r; 3180 numCols = 0; 3181 { 3182 PetscInt aDof, aOff, j; 3183 3184 if (numFields > 1) { 3185 PetscCall(PetscSectionGetFieldDof(refSection, parent, f, &aDof)); 3186 PetscCall(PetscSectionGetFieldOffset(refSection, parent, f, &aOff)); 3187 } else { 3188 PetscCall(PetscSectionGetDof(refSection, parent, &aDof)); 3189 PetscCall(PetscSectionGetOffset(refSection, parent, &aOff)); 3190 } 3191 3192 for (j = 0; j < aDof; j++) cols[numCols++] = aOff + j; 3193 } 3194 PetscCall(PetscMalloc1(cDof * numCols, &refPointFieldMats[p - pRefStart][f])); 3195 /* transpose of constraint matrix */ 3196 PetscCall(MatGetValues(inj, numCols, cols, cDof, rows, refPointFieldMats[p - pRefStart][f])); 3197 } 3198 } 3199 *childrenMats = refPointFieldMats; 3200 PetscCall(PetscFree(rows)); 3201 PetscCall(PetscFree(cols)); 3202 PetscFunctionReturn(PETSC_SUCCESS); 3203 } 3204 3205 static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) 3206 { 3207 PetscDS ds; 3208 PetscScalar ***refPointFieldMats; 3209 PetscInt numFields, pRefStart, pRefEnd, p, f; 3210 PetscSection refConSec, refSection; 3211 3212 PetscFunctionBegin; 3213 refPointFieldMats = *childrenMats; 3214 *childrenMats = NULL; 3215 PetscCall(DMGetDS(refTree, &ds)); 3216 PetscCall(DMGetLocalSection(refTree, &refSection)); 3217 PetscCall(PetscDSGetNumFields(ds, &numFields)); 3218 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL)); 3219 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 3220 for (p = pRefStart; p < pRefEnd; p++) { 3221 PetscInt parent, pDof, parentDof; 3222 3223 PetscCall(DMPlexGetTreeParent(refTree, p, &parent, NULL)); 3224 PetscCall(PetscSectionGetDof(refConSec, p, &pDof)); 3225 PetscCall(PetscSectionGetDof(refSection, parent, &parentDof)); 3226 if (!pDof || !parentDof || parent == p) continue; 3227 3228 for (f = 0; f < numFields; f++) { 3229 PetscInt cDof; 3230 3231 if (numFields > 1) { 3232 PetscCall(PetscSectionGetFieldDof(refConSec, p, f, &cDof)); 3233 } else { 3234 PetscCall(PetscSectionGetDof(refConSec, p, &cDof)); 3235 } 3236 3237 PetscCall(PetscFree(refPointFieldMats[p - pRefStart][f])); 3238 } 3239 PetscCall(PetscFree(refPointFieldMats[p - pRefStart])); 3240 } 3241 PetscCall(PetscFree(refPointFieldMats)); 3242 PetscFunctionReturn(PETSC_SUCCESS); 3243 } 3244 3245 static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree, Mat *injRef) 3246 { 3247 Mat cMatRef; 3248 PetscObject injRefObj; 3249 3250 PetscFunctionBegin; 3251 PetscCall(DMGetDefaultConstraints(refTree, NULL, &cMatRef, NULL)); 3252 PetscCall(PetscObjectQuery((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", &injRefObj)); 3253 *injRef = (Mat)injRefObj; 3254 if (!*injRef) { 3255 PetscCall(DMPlexComputeInjectorReferenceTree(refTree, injRef)); 3256 PetscCall(PetscObjectCompose((PetscObject)cMatRef, "DMPlexComputeInjectorTree_refTree", (PetscObject)*injRef)); 3257 /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */ 3258 PetscCall(PetscObjectDereference((PetscObject)*injRef)); 3259 } 3260 PetscFunctionReturn(PETSC_SUCCESS); 3261 } 3262 3263 static PetscErrorCode DMPlexTransferInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, const PetscInt *childIds, Vec fineVec, PetscInt numFields, PetscInt *offsets, PetscSection *rootMultiSec, PetscSection *multiLeafSec, PetscInt **gatheredIndices, PetscScalar **gatheredValues) 3264 { 3265 PetscInt pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti; 3266 PetscSection globalCoarse, globalFine; 3267 PetscSection localCoarse, localFine, leafIndicesSec; 3268 PetscSection multiRootSec, rootIndicesSec; 3269 PetscInt *leafInds, *rootInds = NULL; 3270 const PetscInt *rootDegrees; 3271 PetscScalar *leafVals = NULL, *rootVals = NULL; 3272 PetscSF coarseToFineEmbedded; 3273 3274 PetscFunctionBegin; 3275 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 3276 PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF)); 3277 PetscCall(DMGetLocalSection(fine, &localFine)); 3278 PetscCall(DMGetGlobalSection(fine, &globalFine)); 3279 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafIndicesSec)); 3280 PetscCall(PetscSectionSetChart(leafIndicesSec, pStartF, pEndF)); 3281 PetscCall(PetscSectionGetMaxDof(localFine, &maxDof)); 3282 { /* winnow fine points that don't have global dofs out of the sf */ 3283 PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices; 3284 const PetscInt *leaves; 3285 3286 PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL)); 3287 for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) { 3288 p = leaves ? leaves[l] : l; 3289 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 3290 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 3291 if ((dof - cdof) > 0) { 3292 numPointsWithDofs++; 3293 3294 PetscCall(PetscSectionGetDof(localFine, p, &dof)); 3295 PetscCall(PetscSectionSetDof(leafIndicesSec, p, dof + 1)); 3296 } 3297 } 3298 PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs)); 3299 PetscCall(PetscSectionSetUp(leafIndicesSec)); 3300 PetscCall(PetscSectionGetStorageSize(leafIndicesSec, &numIndices)); 3301 PetscCall(PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1), &leafInds)); 3302 if (gatheredValues) PetscCall(PetscMalloc1(numIndices, &leafVals)); 3303 for (l = 0, offset = 0; l < nleaves; l++) { 3304 p = leaves ? leaves[l] : l; 3305 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 3306 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 3307 if ((dof - cdof) > 0) { 3308 PetscInt off, gOff; 3309 PetscInt *pInd; 3310 PetscScalar *pVal = NULL; 3311 3312 pointsWithDofs[offset++] = l; 3313 3314 PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off)); 3315 3316 pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds; 3317 if (gatheredValues) { 3318 PetscInt i; 3319 3320 pVal = &leafVals[off + 1]; 3321 for (i = 0; i < dof; i++) pVal[i] = 0.; 3322 } 3323 PetscCall(PetscSectionGetOffset(globalFine, p, &gOff)); 3324 3325 offsets[0] = 0; 3326 if (numFields) { 3327 PetscInt f; 3328 3329 for (f = 0; f < numFields; f++) { 3330 PetscInt fDof; 3331 PetscCall(PetscSectionGetFieldDof(localFine, p, f, &fDof)); 3332 offsets[f + 1] = fDof + offsets[f]; 3333 } 3334 PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, -1, NULL, pInd)); 3335 } else { 3336 PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsets, PETSC_FALSE, NULL, NULL, pInd)); 3337 } 3338 if (gatheredValues) PetscCall(VecGetValues(fineVec, dof, pInd, pVal)); 3339 } 3340 } 3341 PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded)); 3342 PetscCall(PetscFree(pointsWithDofs)); 3343 } 3344 3345 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 3346 PetscCall(DMGetLocalSection(coarse, &localCoarse)); 3347 PetscCall(DMGetGlobalSection(coarse, &globalCoarse)); 3348 3349 { /* there may be the case where an sf root has a parent: broadcast parents back to children */ 3350 MPI_Datatype threeInt; 3351 PetscMPIInt rank; 3352 PetscInt(*parentNodeAndIdCoarse)[3]; 3353 PetscInt(*parentNodeAndIdFine)[3]; 3354 PetscInt p, nleaves, nleavesToParents; 3355 PetscSF pointSF, sfToParents; 3356 const PetscInt *ilocal; 3357 const PetscSFNode *iremote; 3358 PetscSFNode *iremoteToParents; 3359 PetscInt *ilocalToParents; 3360 3361 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)coarse), &rank)); 3362 PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &threeInt)); 3363 PetscCallMPI(MPI_Type_commit(&threeInt)); 3364 PetscCall(PetscMalloc2(pEndC - pStartC, &parentNodeAndIdCoarse, pEndF - pStartF, &parentNodeAndIdFine)); 3365 PetscCall(DMGetPointSF(coarse, &pointSF)); 3366 PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, &iremote)); 3367 for (p = pStartC; p < pEndC; p++) { 3368 PetscInt parent, childId; 3369 PetscCall(DMPlexGetTreeParent(coarse, p, &parent, &childId)); 3370 parentNodeAndIdCoarse[p - pStartC][0] = rank; 3371 parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC; 3372 parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId; 3373 if (nleaves > 0) { 3374 PetscInt leaf = -1; 3375 3376 if (ilocal) { 3377 PetscCall(PetscFindInt(parent, nleaves, ilocal, &leaf)); 3378 } else { 3379 leaf = p - pStartC; 3380 } 3381 if (leaf >= 0) { 3382 parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank; 3383 parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index; 3384 } 3385 } 3386 } 3387 for (p = pStartF; p < pEndF; p++) { 3388 parentNodeAndIdFine[p - pStartF][0] = -1; 3389 parentNodeAndIdFine[p - pStartF][1] = -1; 3390 parentNodeAndIdFine[p - pStartF][2] = -1; 3391 } 3392 PetscCall(PetscSFBcastBegin(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE)); 3393 PetscCall(PetscSFBcastEnd(coarseToFineEmbedded, threeInt, parentNodeAndIdCoarse, parentNodeAndIdFine, MPI_REPLACE)); 3394 for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) { 3395 PetscInt dof; 3396 3397 PetscCall(PetscSectionGetDof(leafIndicesSec, p, &dof)); 3398 if (dof) { 3399 PetscInt off; 3400 3401 PetscCall(PetscSectionGetOffset(leafIndicesSec, p, &off)); 3402 if (gatheredIndices) { 3403 leafInds[off] = PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]); 3404 } else if (gatheredValues) { 3405 leafVals[off] = (PetscScalar)PetscMax(childIds[p - pStartF], parentNodeAndIdFine[p - pStartF][2]); 3406 } 3407 } 3408 if (parentNodeAndIdFine[p - pStartF][0] >= 0) nleavesToParents++; 3409 } 3410 PetscCall(PetscMalloc1(nleavesToParents, &ilocalToParents)); 3411 PetscCall(PetscMalloc1(nleavesToParents, &iremoteToParents)); 3412 for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) { 3413 if (parentNodeAndIdFine[p - pStartF][0] >= 0) { 3414 ilocalToParents[nleavesToParents] = p - pStartF; 3415 iremoteToParents[nleavesToParents].rank = parentNodeAndIdFine[p - pStartF][0]; 3416 iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p - pStartF][1]; 3417 nleavesToParents++; 3418 } 3419 } 3420 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)coarse), &sfToParents)); 3421 PetscCall(PetscSFSetGraph(sfToParents, pEndC - pStartC, nleavesToParents, ilocalToParents, PETSC_OWN_POINTER, iremoteToParents, PETSC_OWN_POINTER)); 3422 PetscCall(PetscSFDestroy(&coarseToFineEmbedded)); 3423 3424 coarseToFineEmbedded = sfToParents; 3425 3426 PetscCall(PetscFree2(parentNodeAndIdCoarse, parentNodeAndIdFine)); 3427 PetscCallMPI(MPI_Type_free(&threeInt)); 3428 } 3429 3430 { /* winnow out coarse points that don't have dofs */ 3431 PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs; 3432 PetscSF sfDofsOnly; 3433 3434 for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) { 3435 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 3436 PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof)); 3437 if ((dof - cdof) > 0) numPointsWithDofs++; 3438 } 3439 PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs)); 3440 for (p = pStartC, offset = 0; p < pEndC; p++) { 3441 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 3442 PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof)); 3443 if ((dof - cdof) > 0) pointsWithDofs[offset++] = p - pStartC; 3444 } 3445 PetscCall(PetscSFCreateEmbeddedRootSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly)); 3446 PetscCall(PetscSFDestroy(&coarseToFineEmbedded)); 3447 PetscCall(PetscFree(pointsWithDofs)); 3448 coarseToFineEmbedded = sfDofsOnly; 3449 } 3450 3451 /* communicate back to the coarse mesh which coarse points have children (that may require injection) */ 3452 PetscCall(PetscSFComputeDegreeBegin(coarseToFineEmbedded, &rootDegrees)); 3453 PetscCall(PetscSFComputeDegreeEnd(coarseToFineEmbedded, &rootDegrees)); 3454 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &multiRootSec)); 3455 PetscCall(PetscSectionSetChart(multiRootSec, pStartC, pEndC)); 3456 for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionSetDof(multiRootSec, p, rootDegrees[p - pStartC])); 3457 PetscCall(PetscSectionSetUp(multiRootSec)); 3458 PetscCall(PetscSectionGetStorageSize(multiRootSec, &numMulti)); 3459 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootIndicesSec)); 3460 { /* distribute the leaf section */ 3461 PetscSF multi, multiInv, indicesSF; 3462 PetscInt *remoteOffsets, numRootIndices; 3463 3464 PetscCall(PetscSFGetMultiSF(coarseToFineEmbedded, &multi)); 3465 PetscCall(PetscSFCreateInverseSF(multi, &multiInv)); 3466 PetscCall(PetscSFDistributeSection(multiInv, leafIndicesSec, &remoteOffsets, rootIndicesSec)); 3467 PetscCall(PetscSFCreateSectionSF(multiInv, leafIndicesSec, remoteOffsets, rootIndicesSec, &indicesSF)); 3468 PetscCall(PetscFree(remoteOffsets)); 3469 PetscCall(PetscSFDestroy(&multiInv)); 3470 PetscCall(PetscSectionGetStorageSize(rootIndicesSec, &numRootIndices)); 3471 if (gatheredIndices) { 3472 PetscCall(PetscMalloc1(numRootIndices, &rootInds)); 3473 PetscCall(PetscSFBcastBegin(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE)); 3474 PetscCall(PetscSFBcastEnd(indicesSF, MPIU_INT, leafInds, rootInds, MPI_REPLACE)); 3475 } 3476 if (gatheredValues) { 3477 PetscCall(PetscMalloc1(numRootIndices, &rootVals)); 3478 PetscCall(PetscSFBcastBegin(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE)); 3479 PetscCall(PetscSFBcastEnd(indicesSF, MPIU_SCALAR, leafVals, rootVals, MPI_REPLACE)); 3480 } 3481 PetscCall(PetscSFDestroy(&indicesSF)); 3482 } 3483 PetscCall(PetscSectionDestroy(&leafIndicesSec)); 3484 PetscCall(PetscFree(leafInds)); 3485 PetscCall(PetscFree(leafVals)); 3486 PetscCall(PetscSFDestroy(&coarseToFineEmbedded)); 3487 *rootMultiSec = multiRootSec; 3488 *multiLeafSec = rootIndicesSec; 3489 if (gatheredIndices) *gatheredIndices = rootInds; 3490 if (gatheredValues) *gatheredValues = rootVals; 3491 PetscFunctionReturn(PETSC_SUCCESS); 3492 } 3493 3494 PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) 3495 { 3496 DM refTree; 3497 PetscSection multiRootSec, rootIndicesSec; 3498 PetscSection globalCoarse, globalFine; 3499 PetscSection localCoarse, localFine; 3500 PetscSection cSecRef; 3501 PetscInt *rootIndices = NULL, *parentIndices, pRefStart, pRefEnd; 3502 Mat injRef; 3503 PetscInt numFields, maxDof; 3504 PetscInt pStartC, pEndC, pStartF, pEndF, p; 3505 PetscInt *offsets, *offsetsCopy, *rowOffsets; 3506 PetscLayout rowMap, colMap; 3507 PetscInt rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO; 3508 PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */ 3509 3510 PetscFunctionBegin; 3511 3512 /* get the templates for the fine-to-coarse injection from the reference tree */ 3513 PetscCall(DMPlexGetReferenceTree(coarse, &refTree)); 3514 PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL)); 3515 PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd)); 3516 PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef)); 3517 3518 PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF)); 3519 PetscCall(DMGetLocalSection(fine, &localFine)); 3520 PetscCall(DMGetGlobalSection(fine, &globalFine)); 3521 PetscCall(PetscSectionGetNumFields(localFine, &numFields)); 3522 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 3523 PetscCall(DMGetLocalSection(coarse, &localCoarse)); 3524 PetscCall(DMGetGlobalSection(coarse, &globalCoarse)); 3525 PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof)); 3526 { 3527 PetscInt maxFields = PetscMax(1, numFields) + 1; 3528 PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets)); 3529 } 3530 3531 PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, childIds, NULL, numFields, offsets, &multiRootSec, &rootIndicesSec, &rootIndices, NULL)); 3532 3533 PetscCall(PetscMalloc1(maxDof, &parentIndices)); 3534 3535 /* count indices */ 3536 PetscCall(MatGetLayouts(mat, &rowMap, &colMap)); 3537 PetscCall(PetscLayoutSetUp(rowMap)); 3538 PetscCall(PetscLayoutSetUp(colMap)); 3539 PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd)); 3540 PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd)); 3541 PetscCall(PetscCalloc2(rowEnd - rowStart, &nnzD, rowEnd - rowStart, &nnzO)); 3542 for (p = pStartC; p < pEndC; p++) { 3543 PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; 3544 3545 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 3546 PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof)); 3547 if ((dof - cdof) <= 0) continue; 3548 PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff)); 3549 3550 rowOffsets[0] = 0; 3551 offsetsCopy[0] = 0; 3552 if (numFields) { 3553 PetscInt f; 3554 3555 for (f = 0; f < numFields; f++) { 3556 PetscInt fDof; 3557 PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof)); 3558 rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; 3559 } 3560 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices)); 3561 } else { 3562 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices)); 3563 rowOffsets[1] = offsetsCopy[0]; 3564 } 3565 3566 PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves)); 3567 PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart)); 3568 leafEnd = leafStart + numLeaves; 3569 for (l = leafStart; l < leafEnd; l++) { 3570 PetscInt numIndices, childId, offset; 3571 const PetscInt *childIndices; 3572 3573 PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices)); 3574 PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset)); 3575 childId = rootIndices[offset++]; 3576 childIndices = &rootIndices[offset]; 3577 numIndices--; 3578 3579 if (childId == -1) { /* equivalent points: scatter */ 3580 PetscInt i; 3581 3582 for (i = 0; i < numIndices; i++) { 3583 PetscInt colIndex = childIndices[i]; 3584 PetscInt rowIndex = parentIndices[i]; 3585 if (rowIndex < 0) continue; 3586 PetscCheck(colIndex >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unconstrained fine and constrained coarse"); 3587 if (colIndex >= colStart && colIndex < colEnd) { 3588 nnzD[rowIndex - rowStart] = 1; 3589 } else { 3590 nnzO[rowIndex - rowStart] = 1; 3591 } 3592 } 3593 } else { 3594 PetscInt parentId, f, lim; 3595 3596 PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL)); 3597 3598 lim = PetscMax(1, numFields); 3599 offsets[0] = 0; 3600 if (numFields) { 3601 PetscInt f; 3602 3603 for (f = 0; f < numFields; f++) { 3604 PetscInt fDof; 3605 PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof)); 3606 3607 offsets[f + 1] = fDof + offsets[f]; 3608 } 3609 } else { 3610 PetscInt cDof; 3611 3612 PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof)); 3613 offsets[1] = cDof; 3614 } 3615 for (f = 0; f < lim; f++) { 3616 PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1]; 3617 PetscInt childStart = offsets[f], childEnd = offsets[f + 1]; 3618 PetscInt i, numD = 0, numO = 0; 3619 3620 for (i = childStart; i < childEnd; i++) { 3621 PetscInt colIndex = childIndices[i]; 3622 3623 if (colIndex < 0) continue; 3624 if (colIndex >= colStart && colIndex < colEnd) { 3625 numD++; 3626 } else { 3627 numO++; 3628 } 3629 } 3630 for (i = parentStart; i < parentEnd; i++) { 3631 PetscInt rowIndex = parentIndices[i]; 3632 3633 if (rowIndex < 0) continue; 3634 nnzD[rowIndex - rowStart] += numD; 3635 nnzO[rowIndex - rowStart] += numO; 3636 } 3637 } 3638 } 3639 } 3640 } 3641 /* preallocate */ 3642 PetscCall(MatXAIJSetPreallocation(mat, 1, nnzD, nnzO, NULL, NULL)); 3643 PetscCall(PetscFree2(nnzD, nnzO)); 3644 /* insert values */ 3645 PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats)); 3646 for (p = pStartC; p < pEndC; p++) { 3647 PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; 3648 3649 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 3650 PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof)); 3651 if ((dof - cdof) <= 0) continue; 3652 PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff)); 3653 3654 rowOffsets[0] = 0; 3655 offsetsCopy[0] = 0; 3656 if (numFields) { 3657 PetscInt f; 3658 3659 for (f = 0; f < numFields; f++) { 3660 PetscInt fDof; 3661 PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof)); 3662 rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; 3663 } 3664 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices)); 3665 } else { 3666 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices)); 3667 rowOffsets[1] = offsetsCopy[0]; 3668 } 3669 3670 PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves)); 3671 PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart)); 3672 leafEnd = leafStart + numLeaves; 3673 for (l = leafStart; l < leafEnd; l++) { 3674 PetscInt numIndices, childId, offset; 3675 const PetscInt *childIndices; 3676 3677 PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices)); 3678 PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset)); 3679 childId = rootIndices[offset++]; 3680 childIndices = &rootIndices[offset]; 3681 numIndices--; 3682 3683 if (childId == -1) { /* equivalent points: scatter */ 3684 PetscInt i; 3685 3686 for (i = 0; i < numIndices; i++) PetscCall(MatSetValue(mat, parentIndices[i], childIndices[i], 1., INSERT_VALUES)); 3687 } else { 3688 PetscInt parentId, f, lim; 3689 3690 PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL)); 3691 3692 lim = PetscMax(1, numFields); 3693 offsets[0] = 0; 3694 if (numFields) { 3695 PetscInt f; 3696 3697 for (f = 0; f < numFields; f++) { 3698 PetscInt fDof; 3699 PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof)); 3700 3701 offsets[f + 1] = fDof + offsets[f]; 3702 } 3703 } else { 3704 PetscInt cDof; 3705 3706 PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof)); 3707 offsets[1] = cDof; 3708 } 3709 for (f = 0; f < lim; f++) { 3710 PetscScalar *childMat = &childrenMats[childId - pRefStart][f][0]; 3711 PetscInt *rowIndices = &parentIndices[rowOffsets[f]]; 3712 const PetscInt *colIndices = &childIndices[offsets[f]]; 3713 3714 PetscCall(MatSetValues(mat, rowOffsets[f + 1] - rowOffsets[f], rowIndices, offsets[f + 1] - offsets[f], colIndices, childMat, INSERT_VALUES)); 3715 } 3716 } 3717 } 3718 } 3719 PetscCall(PetscSectionDestroy(&multiRootSec)); 3720 PetscCall(PetscSectionDestroy(&rootIndicesSec)); 3721 PetscCall(PetscFree(parentIndices)); 3722 PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats)); 3723 PetscCall(PetscFree(rootIndices)); 3724 PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets)); 3725 3726 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 3727 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 3728 PetscFunctionReturn(PETSC_SUCCESS); 3729 } 3730 3731 static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom) 3732 { 3733 PetscSF coarseToFineEmbedded; 3734 PetscSection globalCoarse, globalFine; 3735 PetscSection localCoarse, localFine; 3736 PetscSection aSec, cSec; 3737 PetscSection rootValuesSec; 3738 PetscSection leafValuesSec; 3739 PetscScalar *rootValues, *leafValues; 3740 IS aIS; 3741 const PetscInt *anchors; 3742 Mat cMat; 3743 PetscInt numFields; 3744 PetscInt pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd; 3745 PetscInt aStart, aEnd, cStart, cEnd; 3746 PetscInt *maxChildIds; 3747 PetscInt *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO; 3748 PetscFV fv = NULL; 3749 PetscInt dim, numFVcomps = -1, fvField = -1; 3750 DM cellDM = NULL, gradDM = NULL; 3751 const PetscScalar *cellGeomArray = NULL; 3752 const PetscScalar *gradArray = NULL; 3753 3754 PetscFunctionBegin; 3755 PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE)); 3756 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 3757 PetscCall(DMPlexGetSimplexOrBoxCells(coarse, 0, &cellStart, &cellEnd)); 3758 PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF)); 3759 PetscCall(DMGetGlobalSection(fine, &globalFine)); 3760 PetscCall(DMGetCoordinateDim(coarse, &dim)); 3761 { /* winnow fine points that don't have global dofs out of the sf */ 3762 PetscInt nleaves, l; 3763 const PetscInt *leaves; 3764 PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs; 3765 3766 PetscCall(PetscSFGetGraph(coarseToFine, NULL, &nleaves, &leaves, NULL)); 3767 3768 for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) { 3769 PetscInt p = leaves ? leaves[l] : l; 3770 3771 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 3772 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 3773 if ((dof - cdof) > 0) numPointsWithDofs++; 3774 } 3775 PetscCall(PetscMalloc1(numPointsWithDofs, &pointsWithDofs)); 3776 for (l = 0, offset = 0; l < nleaves; l++) { 3777 PetscInt p = leaves ? leaves[l] : l; 3778 3779 PetscCall(PetscSectionGetDof(globalFine, p, &dof)); 3780 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &cdof)); 3781 if ((dof - cdof) > 0) pointsWithDofs[offset++] = l; 3782 } 3783 PetscCall(PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded)); 3784 PetscCall(PetscFree(pointsWithDofs)); 3785 } 3786 /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */ 3787 PetscCall(PetscMalloc1(pEndC - pStartC, &maxChildIds)); 3788 for (p = pStartC; p < pEndC; p++) maxChildIds[p - pStartC] = -2; 3789 PetscCall(PetscSFReduceBegin(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX)); 3790 PetscCall(PetscSFReduceEnd(coarseToFineEmbedded, MPIU_INT, cids, maxChildIds, MPIU_MAX)); 3791 3792 PetscCall(DMGetLocalSection(coarse, &localCoarse)); 3793 PetscCall(DMGetGlobalSection(coarse, &globalCoarse)); 3794 3795 PetscCall(DMPlexGetAnchors(coarse, &aSec, &aIS)); 3796 PetscCall(ISGetIndices(aIS, &anchors)); 3797 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 3798 3799 PetscCall(DMGetDefaultConstraints(coarse, &cSec, &cMat, NULL)); 3800 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 3801 3802 /* create sections that will send to children the indices and matrices they will need to construct the interpolator */ 3803 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)coarse), &rootValuesSec)); 3804 PetscCall(PetscSectionSetChart(rootValuesSec, pStartC, pEndC)); 3805 PetscCall(PetscSectionGetNumFields(localCoarse, &numFields)); 3806 { 3807 PetscInt maxFields = PetscMax(1, numFields) + 1; 3808 PetscCall(PetscMalloc7(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &newOffsets, maxFields, &newOffsetsCopy, maxFields, &rowOffsets, maxFields, &numD, maxFields, &numO)); 3809 } 3810 if (grad) { 3811 PetscInt i; 3812 3813 PetscCall(VecGetDM(cellGeom, &cellDM)); 3814 PetscCall(VecGetArrayRead(cellGeom, &cellGeomArray)); 3815 PetscCall(VecGetDM(grad, &gradDM)); 3816 PetscCall(VecGetArrayRead(grad, &gradArray)); 3817 for (i = 0; i < PetscMax(1, numFields); i++) { 3818 PetscObject obj; 3819 PetscClassId id; 3820 3821 PetscCall(DMGetField(coarse, i, NULL, &obj)); 3822 PetscCall(PetscObjectGetClassId(obj, &id)); 3823 if (id == PETSCFV_CLASSID) { 3824 fv = (PetscFV)obj; 3825 PetscCall(PetscFVGetNumComponents(fv, &numFVcomps)); 3826 fvField = i; 3827 break; 3828 } 3829 } 3830 } 3831 3832 for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */ 3833 PetscInt dof; 3834 PetscInt maxChildId = maxChildIds[p - pStartC]; 3835 PetscInt numValues = 0; 3836 3837 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 3838 if (dof < 0) dof = -(dof + 1); 3839 offsets[0] = 0; 3840 newOffsets[0] = 0; 3841 if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */ 3842 PetscInt *closure = NULL, closureSize, cl; 3843 3844 PetscCall(DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 3845 for (cl = 0; cl < closureSize; cl++) { /* get the closure */ 3846 PetscInt c = closure[2 * cl], clDof; 3847 3848 PetscCall(PetscSectionGetDof(localCoarse, c, &clDof)); 3849 numValues += clDof; 3850 } 3851 PetscCall(DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure)); 3852 } else if (maxChildId == -1) { 3853 PetscCall(PetscSectionGetDof(localCoarse, p, &numValues)); 3854 } 3855 /* we will pack the column indices with the field offsets */ 3856 if (maxChildId >= 0 && grad && p >= cellStart && p < cellEnd) { 3857 /* also send the centroid, and the gradient */ 3858 numValues += dim * (1 + numFVcomps); 3859 } 3860 PetscCall(PetscSectionSetDof(rootValuesSec, p, numValues)); 3861 } 3862 PetscCall(PetscSectionSetUp(rootValuesSec)); 3863 { 3864 PetscInt numRootValues; 3865 const PetscScalar *coarseArray; 3866 3867 PetscCall(PetscSectionGetStorageSize(rootValuesSec, &numRootValues)); 3868 PetscCall(PetscMalloc1(numRootValues, &rootValues)); 3869 PetscCall(VecGetArrayRead(vecCoarseLocal, &coarseArray)); 3870 for (p = pStartC; p < pEndC; p++) { 3871 PetscInt numValues; 3872 PetscInt pValOff; 3873 PetscScalar *pVal; 3874 PetscInt maxChildId = maxChildIds[p - pStartC]; 3875 3876 PetscCall(PetscSectionGetDof(rootValuesSec, p, &numValues)); 3877 if (!numValues) continue; 3878 PetscCall(PetscSectionGetOffset(rootValuesSec, p, &pValOff)); 3879 pVal = &(rootValues[pValOff]); 3880 if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */ 3881 PetscInt closureSize = numValues; 3882 PetscCall(DMPlexVecGetClosure(coarse, NULL, vecCoarseLocal, p, &closureSize, &pVal)); 3883 if (grad && p >= cellStart && p < cellEnd) { 3884 PetscFVCellGeom *cg; 3885 PetscScalar *gradVals = NULL; 3886 PetscInt i; 3887 3888 pVal += (numValues - dim * (1 + numFVcomps)); 3889 3890 PetscCall(DMPlexPointLocalRead(cellDM, p, cellGeomArray, (void *)&cg)); 3891 for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i]; 3892 pVal += dim; 3893 PetscCall(DMPlexPointGlobalRead(gradDM, p, gradArray, (void *)&gradVals)); 3894 for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i]; 3895 } 3896 } else if (maxChildId == -1) { 3897 PetscInt lDof, lOff, i; 3898 3899 PetscCall(PetscSectionGetDof(localCoarse, p, &lDof)); 3900 PetscCall(PetscSectionGetOffset(localCoarse, p, &lOff)); 3901 for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i]; 3902 } 3903 } 3904 PetscCall(VecRestoreArrayRead(vecCoarseLocal, &coarseArray)); 3905 PetscCall(PetscFree(maxChildIds)); 3906 } 3907 { 3908 PetscSF valuesSF; 3909 PetscInt *remoteOffsetsValues, numLeafValues; 3910 3911 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)fine), &leafValuesSec)); 3912 PetscCall(PetscSFDistributeSection(coarseToFineEmbedded, rootValuesSec, &remoteOffsetsValues, leafValuesSec)); 3913 PetscCall(PetscSFCreateSectionSF(coarseToFineEmbedded, rootValuesSec, remoteOffsetsValues, leafValuesSec, &valuesSF)); 3914 PetscCall(PetscSFDestroy(&coarseToFineEmbedded)); 3915 PetscCall(PetscFree(remoteOffsetsValues)); 3916 PetscCall(PetscSectionGetStorageSize(leafValuesSec, &numLeafValues)); 3917 PetscCall(PetscMalloc1(numLeafValues, &leafValues)); 3918 PetscCall(PetscSFBcastBegin(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE)); 3919 PetscCall(PetscSFBcastEnd(valuesSF, MPIU_SCALAR, rootValues, leafValues, MPI_REPLACE)); 3920 PetscCall(PetscSFDestroy(&valuesSF)); 3921 PetscCall(PetscFree(rootValues)); 3922 PetscCall(PetscSectionDestroy(&rootValuesSec)); 3923 } 3924 PetscCall(DMGetLocalSection(fine, &localFine)); 3925 { 3926 PetscInt maxDof; 3927 PetscInt *rowIndices; 3928 DM refTree; 3929 PetscInt **refPointFieldN; 3930 PetscScalar ***refPointFieldMats; 3931 PetscSection refConSec, refAnSec; 3932 PetscInt pRefStart, pRefEnd, leafStart, leafEnd; 3933 PetscScalar *pointWork; 3934 3935 PetscCall(PetscSectionGetMaxDof(localFine, &maxDof)); 3936 PetscCall(DMGetWorkArray(fine, maxDof, MPIU_INT, &rowIndices)); 3937 PetscCall(DMGetWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork)); 3938 PetscCall(DMPlexGetReferenceTree(fine, &refTree)); 3939 PetscCall(DMCopyDisc(fine, refTree)); 3940 PetscCall(DMPlexReferenceTreeGetChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 3941 PetscCall(DMGetDefaultConstraints(refTree, &refConSec, NULL, NULL)); 3942 PetscCall(DMPlexGetAnchors(refTree, &refAnSec, NULL)); 3943 PetscCall(PetscSectionGetChart(refConSec, &pRefStart, &pRefEnd)); 3944 PetscCall(PetscSectionGetChart(leafValuesSec, &leafStart, &leafEnd)); 3945 PetscCall(DMPlexGetSimplexOrBoxCells(fine, 0, &cellStart, &cellEnd)); 3946 for (p = leafStart; p < leafEnd; p++) { 3947 PetscInt gDof, gcDof, gOff, lDof; 3948 PetscInt numValues, pValOff; 3949 PetscInt childId; 3950 const PetscScalar *pVal; 3951 const PetscScalar *fvGradData = NULL; 3952 3953 PetscCall(PetscSectionGetDof(globalFine, p, &gDof)); 3954 PetscCall(PetscSectionGetDof(localFine, p, &lDof)); 3955 PetscCall(PetscSectionGetConstraintDof(globalFine, p, &gcDof)); 3956 if ((gDof - gcDof) <= 0) continue; 3957 PetscCall(PetscSectionGetOffset(globalFine, p, &gOff)); 3958 PetscCall(PetscSectionGetDof(leafValuesSec, p, &numValues)); 3959 if (!numValues) continue; 3960 PetscCall(PetscSectionGetOffset(leafValuesSec, p, &pValOff)); 3961 pVal = &leafValues[pValOff]; 3962 offsets[0] = 0; 3963 offsetsCopy[0] = 0; 3964 newOffsets[0] = 0; 3965 newOffsetsCopy[0] = 0; 3966 childId = cids[p - pStartF]; 3967 if (numFields) { 3968 PetscInt f; 3969 for (f = 0; f < numFields; f++) { 3970 PetscInt rowDof; 3971 3972 PetscCall(PetscSectionGetFieldDof(localFine, p, f, &rowDof)); 3973 offsets[f + 1] = offsets[f] + rowDof; 3974 offsetsCopy[f + 1] = offsets[f + 1]; 3975 /* TODO: closure indices */ 3976 newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]); 3977 } 3978 PetscCall(DMPlexGetIndicesPointFields_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, rowIndices)); 3979 } else { 3980 offsets[0] = 0; 3981 offsets[1] = lDof; 3982 newOffsets[0] = 0; 3983 newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0]; 3984 PetscCall(DMPlexGetIndicesPoint_Internal(localFine, PETSC_FALSE, p, gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, rowIndices)); 3985 } 3986 if (childId == -1) { /* no child interpolation: one nnz per */ 3987 PetscCall(VecSetValues(vecFine, numValues, rowIndices, pVal, INSERT_VALUES)); 3988 } else { 3989 PetscInt f; 3990 3991 if (grad && p >= cellStart && p < cellEnd) { 3992 numValues -= (dim * (1 + numFVcomps)); 3993 fvGradData = &pVal[numValues]; 3994 } 3995 for (f = 0; f < PetscMax(1, numFields); f++) { 3996 const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f]; 3997 PetscInt numRows = offsets[f + 1] - offsets[f]; 3998 PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; 3999 const PetscScalar *cVal = &pVal[newOffsets[f]]; 4000 PetscScalar *rVal = &pointWork[offsets[f]]; 4001 PetscInt i, j; 4002 4003 #if 0 4004 PetscCall(PetscInfo(coarse,"childId %" PetscInt_FMT ", numRows %" PetscInt_FMT ", numCols %" PetscInt_FMT ", refPointFieldN %" PetscInt_FMT " maxDof %" PetscInt_FMT "\n",childId,numRows,numCols,refPointFieldN[childId - pRefStart][f], maxDof)); 4005 #endif 4006 for (i = 0; i < numRows; i++) { 4007 PetscScalar val = 0.; 4008 for (j = 0; j < numCols; j++) val += childMat[i * numCols + j] * cVal[j]; 4009 rVal[i] = val; 4010 } 4011 if (f == fvField && p >= cellStart && p < cellEnd) { 4012 PetscReal centroid[3]; 4013 PetscScalar diff[3]; 4014 const PetscScalar *parentCentroid = &fvGradData[0]; 4015 const PetscScalar *gradient = &fvGradData[dim]; 4016 4017 PetscCall(DMPlexComputeCellGeometryFVM(fine, p, NULL, centroid, NULL)); 4018 for (i = 0; i < dim; i++) diff[i] = centroid[i] - parentCentroid[i]; 4019 for (i = 0; i < numFVcomps; i++) { 4020 PetscScalar val = 0.; 4021 4022 for (j = 0; j < dim; j++) val += gradient[dim * i + j] * diff[j]; 4023 rVal[i] += val; 4024 } 4025 } 4026 PetscCall(VecSetValues(vecFine, numRows, &rowIndices[offsets[f]], rVal, INSERT_VALUES)); 4027 } 4028 } 4029 } 4030 PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices(refTree, &refPointFieldMats, &refPointFieldN)); 4031 PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_SCALAR, &pointWork)); 4032 PetscCall(DMRestoreWorkArray(fine, maxDof, MPIU_INT, &rowIndices)); 4033 } 4034 PetscCall(PetscFree(leafValues)); 4035 PetscCall(PetscSectionDestroy(&leafValuesSec)); 4036 PetscCall(PetscFree7(offsets, offsetsCopy, newOffsets, newOffsetsCopy, rowOffsets, numD, numO)); 4037 PetscCall(ISRestoreIndices(aIS, &anchors)); 4038 PetscFunctionReturn(PETSC_SUCCESS); 4039 } 4040 4041 static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids) 4042 { 4043 DM refTree; 4044 PetscSection multiRootSec, rootIndicesSec; 4045 PetscSection globalCoarse, globalFine; 4046 PetscSection localCoarse, localFine; 4047 PetscSection cSecRef; 4048 PetscInt *parentIndices, pRefStart, pRefEnd; 4049 PetscScalar *rootValues, *parentValues; 4050 Mat injRef; 4051 PetscInt numFields, maxDof; 4052 PetscInt pStartC, pEndC, pStartF, pEndF, p; 4053 PetscInt *offsets, *offsetsCopy, *rowOffsets; 4054 PetscLayout rowMap, colMap; 4055 PetscInt rowStart, rowEnd, colStart, colEnd; 4056 PetscScalar ***childrenMats = NULL; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */ 4057 4058 PetscFunctionBegin; 4059 4060 /* get the templates for the fine-to-coarse injection from the reference tree */ 4061 PetscCall(VecSetOption(vecFine, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE)); 4062 PetscCall(VecSetOption(vecCoarse, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE)); 4063 PetscCall(DMPlexGetReferenceTree(coarse, &refTree)); 4064 PetscCall(DMCopyDisc(coarse, refTree)); 4065 PetscCall(DMGetDefaultConstraints(refTree, &cSecRef, NULL, NULL)); 4066 PetscCall(PetscSectionGetChart(cSecRef, &pRefStart, &pRefEnd)); 4067 PetscCall(DMPlexReferenceTreeGetInjector(refTree, &injRef)); 4068 4069 PetscCall(DMPlexGetChart(fine, &pStartF, &pEndF)); 4070 PetscCall(DMGetLocalSection(fine, &localFine)); 4071 PetscCall(DMGetGlobalSection(fine, &globalFine)); 4072 PetscCall(PetscSectionGetNumFields(localFine, &numFields)); 4073 PetscCall(DMPlexGetChart(coarse, &pStartC, &pEndC)); 4074 PetscCall(DMGetLocalSection(coarse, &localCoarse)); 4075 PetscCall(DMGetGlobalSection(coarse, &globalCoarse)); 4076 PetscCall(PetscSectionGetMaxDof(localCoarse, &maxDof)); 4077 { 4078 PetscInt maxFields = PetscMax(1, numFields) + 1; 4079 PetscCall(PetscMalloc3(maxFields, &offsets, maxFields, &offsetsCopy, maxFields, &rowOffsets)); 4080 } 4081 4082 PetscCall(DMPlexTransferInjectorTree(coarse, fine, coarseToFine, cids, vecFine, numFields, offsets, &multiRootSec, &rootIndicesSec, NULL, &rootValues)); 4083 4084 PetscCall(PetscMalloc2(maxDof, &parentIndices, maxDof, &parentValues)); 4085 4086 /* count indices */ 4087 PetscCall(VecGetLayout(vecFine, &colMap)); 4088 PetscCall(VecGetLayout(vecCoarse, &rowMap)); 4089 PetscCall(PetscLayoutSetUp(rowMap)); 4090 PetscCall(PetscLayoutSetUp(colMap)); 4091 PetscCall(PetscLayoutGetRange(rowMap, &rowStart, &rowEnd)); 4092 PetscCall(PetscLayoutGetRange(colMap, &colStart, &colEnd)); 4093 /* insert values */ 4094 PetscCall(DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree, injRef, &childrenMats)); 4095 for (p = pStartC; p < pEndC; p++) { 4096 PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; 4097 PetscBool contribute = PETSC_FALSE; 4098 4099 PetscCall(PetscSectionGetDof(globalCoarse, p, &dof)); 4100 PetscCall(PetscSectionGetConstraintDof(globalCoarse, p, &cdof)); 4101 if ((dof - cdof) <= 0) continue; 4102 PetscCall(PetscSectionGetDof(localCoarse, p, &dof)); 4103 PetscCall(PetscSectionGetOffset(globalCoarse, p, &gOff)); 4104 4105 rowOffsets[0] = 0; 4106 offsetsCopy[0] = 0; 4107 if (numFields) { 4108 PetscInt f; 4109 4110 for (f = 0; f < numFields; f++) { 4111 PetscInt fDof; 4112 PetscCall(PetscSectionGetFieldDof(localCoarse, p, f, &fDof)); 4113 rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; 4114 } 4115 PetscCall(DMPlexGetIndicesPointFields_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, -1, NULL, parentIndices)); 4116 } else { 4117 PetscCall(DMPlexGetIndicesPoint_Internal(localCoarse, PETSC_FALSE, p, gOff < 0 ? -(gOff + 1) : gOff, offsetsCopy, PETSC_FALSE, NULL, NULL, parentIndices)); 4118 rowOffsets[1] = offsetsCopy[0]; 4119 } 4120 4121 PetscCall(PetscSectionGetDof(multiRootSec, p, &numLeaves)); 4122 PetscCall(PetscSectionGetOffset(multiRootSec, p, &leafStart)); 4123 leafEnd = leafStart + numLeaves; 4124 for (l = 0; l < dof; l++) parentValues[l] = 0.; 4125 for (l = leafStart; l < leafEnd; l++) { 4126 PetscInt numIndices, childId, offset; 4127 const PetscScalar *childValues; 4128 4129 PetscCall(PetscSectionGetDof(rootIndicesSec, l, &numIndices)); 4130 PetscCall(PetscSectionGetOffset(rootIndicesSec, l, &offset)); 4131 childId = (PetscInt)PetscRealPart(rootValues[offset++]); 4132 childValues = &rootValues[offset]; 4133 numIndices--; 4134 4135 if (childId == -2) { /* skip */ 4136 continue; 4137 } else if (childId == -1) { /* equivalent points: scatter */ 4138 PetscInt m; 4139 4140 contribute = PETSC_TRUE; 4141 for (m = 0; m < numIndices; m++) parentValues[m] = childValues[m]; 4142 } else { /* contributions from children: sum with injectors from reference tree */ 4143 PetscInt parentId, f, lim; 4144 4145 contribute = PETSC_TRUE; 4146 PetscCall(DMPlexGetTreeParent(refTree, childId, &parentId, NULL)); 4147 4148 lim = PetscMax(1, numFields); 4149 offsets[0] = 0; 4150 if (numFields) { 4151 PetscInt f; 4152 4153 for (f = 0; f < numFields; f++) { 4154 PetscInt fDof; 4155 PetscCall(PetscSectionGetFieldDof(cSecRef, childId, f, &fDof)); 4156 4157 offsets[f + 1] = fDof + offsets[f]; 4158 } 4159 } else { 4160 PetscInt cDof; 4161 4162 PetscCall(PetscSectionGetDof(cSecRef, childId, &cDof)); 4163 offsets[1] = cDof; 4164 } 4165 for (f = 0; f < lim; f++) { 4166 PetscScalar *childMat = &childrenMats[childId - pRefStart][f][0]; 4167 PetscInt n = offsets[f + 1] - offsets[f]; 4168 PetscInt m = rowOffsets[f + 1] - rowOffsets[f]; 4169 PetscInt i, j; 4170 const PetscScalar *colValues = &childValues[offsets[f]]; 4171 4172 for (i = 0; i < m; i++) { 4173 PetscScalar val = 0.; 4174 for (j = 0; j < n; j++) val += childMat[n * i + j] * colValues[j]; 4175 parentValues[rowOffsets[f] + i] += val; 4176 } 4177 } 4178 } 4179 } 4180 if (contribute) PetscCall(VecSetValues(vecCoarse, dof, parentIndices, parentValues, INSERT_VALUES)); 4181 } 4182 PetscCall(PetscSectionDestroy(&multiRootSec)); 4183 PetscCall(PetscSectionDestroy(&rootIndicesSec)); 4184 PetscCall(PetscFree2(parentIndices, parentValues)); 4185 PetscCall(DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree, injRef, &childrenMats)); 4186 PetscCall(PetscFree(rootValues)); 4187 PetscCall(PetscFree3(offsets, offsetsCopy, rowOffsets)); 4188 PetscFunctionReturn(PETSC_SUCCESS); 4189 } 4190 4191 /*@ 4192 DMPlexTransferVecTree - transfer a vector between two meshes that differ from each other by refinement/coarsening 4193 that can be represented by a common reference tree used by both. This routine can be used for a combination of 4194 coarsening and refinement at the same time. 4195 4196 Collective 4197 4198 Input Parameters: 4199 + dmIn - The `DMPLEX` mesh for the input vector 4200 . dmOut - The second `DMPLEX` mesh 4201 . vecIn - The input vector 4202 . sfRefine - A star forest indicating points in the mesh `dmIn` (roots in the star forest) that are parents to points in 4203 the mesh `dmOut` (leaves in the star forest), i.e. where `dmOut` is more refined than `dmIn` 4204 . sfCoarsen - A star forest indicating points in the mesh `dmOut` (roots in the star forest) that are parents to points in 4205 the mesh `dmIn` (leaves in the star forest), i.e. where `dmOut` is more coarsened than `dmIn` 4206 . cidsRefine - The childIds of the points in `dmOut`. These childIds relate back to the reference tree: childid[j] = k implies 4207 that mesh point j of `dmOut` was refined from a point in `dmIn` just as the mesh point k in the reference 4208 tree was refined from its parent. childid[j] = -1 indicates that the point j in `dmOut` is exactly 4209 equivalent to its root in `dmIn`, so no interpolation is necessary. childid[j] = -2 indicates that this 4210 point j in `dmOut` is not a leaf of `sfRefine`. 4211 . cidsCoarsen - The childIds of the points in `dmIn`. These childIds relate back to the reference tree: childid[j] = k implies 4212 that mesh point j of dmIn coarsens to a point in `dmOut` just as the mesh point k in the reference 4213 tree coarsens to its parent. childid[j] = -2 indicates that point j in `dmOut` is not a leaf in `sfCoarsen`. 4214 . useBCs - `PETSC_TRUE` indicates that boundary values should be inserted into `vecIn` before transfer. 4215 - time - Used if boundary values are time dependent. 4216 4217 Output Parameters: 4218 . vecOut - Using interpolation and injection operators calculated on the reference tree, the transferred 4219 projection of `vecIn` from `dmIn` to `dmOut`. Note that any field discretized with a `PetscFV` finite volume 4220 method that uses gradient reconstruction will use reconstructed gradients when interpolating from 4221 coarse points to fine points. 4222 4223 Level: developer 4224 4225 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `Vec`, `PetscFV`, `DMPlexSetReferenceTree()`, `DMPlexGetReferenceTree()`, `PetscFVGetComputeGradients()` 4226 @*/ 4227 PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfRefine, PetscSF sfCoarsen, PetscInt *cidsRefine, PetscInt *cidsCoarsen, PetscBool useBCs, PetscReal time) 4228 { 4229 PetscFunctionBegin; 4230 PetscCall(VecSet(vecOut, 0.0)); 4231 if (sfRefine) { 4232 Vec vecInLocal; 4233 DM dmGrad = NULL; 4234 Vec faceGeom = NULL, cellGeom = NULL, grad = NULL; 4235 4236 PetscCall(DMGetLocalVector(dmIn, &vecInLocal)); 4237 PetscCall(VecSet(vecInLocal, 0.0)); 4238 { 4239 PetscInt numFields, i; 4240 4241 PetscCall(DMGetNumFields(dmIn, &numFields)); 4242 for (i = 0; i < numFields; i++) { 4243 PetscObject obj; 4244 PetscClassId classid; 4245 4246 PetscCall(DMGetField(dmIn, i, NULL, &obj)); 4247 PetscCall(PetscObjectGetClassId(obj, &classid)); 4248 if (classid == PETSCFV_CLASSID) { 4249 PetscCall(DMPlexGetDataFVM(dmIn, (PetscFV)obj, &cellGeom, &faceGeom, &dmGrad)); 4250 break; 4251 } 4252 } 4253 } 4254 if (useBCs) PetscCall(DMPlexInsertBoundaryValues(dmIn, PETSC_TRUE, vecInLocal, time, faceGeom, cellGeom, NULL)); 4255 PetscCall(DMGlobalToLocalBegin(dmIn, vecIn, INSERT_VALUES, vecInLocal)); 4256 PetscCall(DMGlobalToLocalEnd(dmIn, vecIn, INSERT_VALUES, vecInLocal)); 4257 if (dmGrad) { 4258 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 4259 PetscCall(DMPlexReconstructGradientsFVM(dmIn, vecInLocal, grad)); 4260 } 4261 PetscCall(DMPlexTransferVecTree_Interpolate(dmIn, vecInLocal, dmOut, vecOut, sfRefine, cidsRefine, grad, cellGeom)); 4262 PetscCall(DMRestoreLocalVector(dmIn, &vecInLocal)); 4263 if (dmGrad) PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 4264 } 4265 if (sfCoarsen) PetscCall(DMPlexTransferVecTree_Inject(dmIn, vecIn, dmOut, vecOut, sfCoarsen, cidsCoarsen)); 4266 PetscCall(VecAssemblyBegin(vecOut)); 4267 PetscCall(VecAssemblyEnd(vecOut)); 4268 PetscFunctionReturn(PETSC_SUCCESS); 4269 } 4270