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