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