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