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