#include /*I "petscdmplex.h" I*/ #include <../src/sys/utils/hash.h> #include #include #include #include /** hierarchy routines */ #undef __FUNCT__ #define __FUNCT__ "DMPlexSetReferenceTree" /*@ DMPlexSetReferenceTree - set the reference tree for hierarchically non-conforming meshes. Not collective Input Parameters: + dm - The DMPlex object - ref - The reference tree DMPlex object Level: intermediate .seealso: DMPlexGetReferenceTree(), DMPlexCreateDefaultReferenceTree() @*/ PetscErrorCode DMPlexSetReferenceTree(DM dm, DM ref) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); if (ref) {PetscValidHeaderSpecific(ref, DM_CLASSID, 2);} ierr = PetscObjectReference((PetscObject)ref);CHKERRQ(ierr); ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr); mesh->referenceTree = ref; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetReferenceTree" /*@ DMPlexGetReferenceTree - get the reference tree for hierarchically non-conforming meshes. Not collective Input Parameters: . dm - The DMPlex object Output Parameters . ref - The reference tree DMPlex object Level: intermediate .seealso: DMPlexSetReferenceTree(), DMPlexCreateDefaultReferenceTree() @*/ PetscErrorCode DMPlexGetReferenceTree(DM dm, DM *ref) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidPointer(ref,2); *ref = mesh->referenceTree; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry_Default" static PetscErrorCode DMPlexReferenceTreeGetChildSymmetry_Default(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) { PetscInt coneSize, dStart, dEnd, dim, ABswap, oAvert, oBvert, ABswapVert; PetscErrorCode ierr; PetscFunctionBegin; if (parentOrientA == parentOrientB) { if (childOrientB) *childOrientB = childOrientA; if (childB) *childB = childA; PetscFunctionReturn(0); } for (dim = 0; dim < 3; dim++) { ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr); if (parent >= dStart && parent <= dEnd) { break; } } if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim); if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children"); if (childA < dStart || childA >= dEnd) { /* this is a lower-dimensional child: bootstrap */ PetscInt size, i, sA = -1, sB, sOrientB, sConeSize; const PetscInt *supp, *coneA, *coneB, *oA, *oB; ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr); ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr); /* find a point sA in supp(childA) that has the same parent */ for (i = 0; i < size; i++) { PetscInt sParent; sA = supp[i]; if (sA == parent) continue; ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr); if (sParent == parent) { break; } } if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children"); /* find out which point sB is in an equivalent position to sA under * parentOrientB */ ierr = DMPlexReferenceTreeGetChildSymmetry_Default(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr); ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr); /* step through the cone of sA in natural order */ for (i = 0; i < sConeSize; i++) { if (coneA[i] == childA) { /* if childA is at position i in coneA, * then we want the point that is at sOrientB*i in coneB */ PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize); if (childB) *childB = coneB[j]; if (childOrientB) { PetscInt oBtrue; ierr = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr); /* compose sOrientB and oB[j] */ if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge"); /* we may have to flip an edge */ oBtrue = coneSize ? ((sOrientB >= 0) ? oB[j] : -(oB[j] + 2)) : 0; ABswap = DihedralSwap(coneSize,oA[i],oBtrue);CHKERRQ(ierr); *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap); } break; } } if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch"); PetscFunctionReturn(0); } /* get the cone size and symmetry swap */ ierr = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr); ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB); if (dim == 2) { /* orientations refer to cones: we want them to refer to vertices: * if it's a rotation, they are the same, but if the order is reversed, a * permutation that puts side i first does *not* put vertex i first */ oAvert = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1); oBvert = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1); ABswapVert = DihedralSwap(coneSize, oAvert, oBvert); } else { ABswapVert = ABswap; } if (childB) { /* assume that each child corresponds to a vertex, in the same order */ PetscInt p, posA = -1, numChildren, i; const PetscInt *children; /* count which position the child is in */ ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr); for (i = 0; i < numChildren; i++) { p = children[i]; if (p == childA) { posA = i; break; } } if (posA >= coneSize) { /* this is the triangle in the middle of a uniformly refined triangle: it * is invariant */ if (dim != 2 || posA != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Expected a middle triangle, got something else"); *childB = childA; } else { /* figure out position B by applying ABswapVert */ PetscInt posB; posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize); if (childB) *childB = children[posB]; } } if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeGetChildSymmetry" /*@ DMPlexReferenceTreeGetChildSymmetry - Given a reference tree, transform a childid and orientation from one parent frame to another Input Parameters: + dm - the reference tree DMPlex object . parent - the parent point . parentOrientA - the reference orientation for describing the parent . childOrientA - the reference orientation for describing the child . childA - the reference childID for describing the child - parentOrientB - the new orientation for describing the parent Output Parameters: + childOrientB - if not NULL, set to the new oreintation for describing the child . childB - if not NULL, the new childID for describing the child Level: developer .seealso: DMPlexGetReferenceTree(), DMPlexSetReferenceTree(), DMPlexSetTree() @*/ PetscErrorCode DMPlexReferenceTreeGetChildSymmetry(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); if (!mesh->getchildsymmetry) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlexReferenceTreeGetChildSymmetry not implemented"); ierr = mesh->getchildsymmetry(dm,parent,parentOrientA,childOrientA,childA,parentOrientB,childOrientB,childB);CHKERRQ(ierr); PetscFunctionReturn(0); } static PetscErrorCode DMPlexSetTree_Internal(DM,PetscSection,PetscInt*,PetscInt*,PetscBool,PetscBool); #undef __FUNCT__ #define __FUNCT__ "DMPlexCreateReferenceTree_Union" PetscErrorCode DMPlexCreateReferenceTree_Union(DM K, DM Kref, const char *labelName, DM *ref) { MPI_Comm comm; PetscInt dim, p, pStart, pEnd, pRefStart, pRefEnd, d, offset, parentSize, *parents, *childIDs; PetscInt *permvals, *unionCones, *coneSizes, *unionOrientations, numUnionPoints, *numDimPoints, numCones, numVerts; DMLabel identity, identityRef; PetscSection unionSection, unionConeSection, parentSection; PetscScalar *unionCoords; IS perm; PetscErrorCode ierr; PetscFunctionBegin; comm = PetscObjectComm((PetscObject)K); ierr = DMGetDimension(K, &dim);CHKERRQ(ierr); ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr); ierr = DMGetLabel(K, labelName, &identity);CHKERRQ(ierr); ierr = DMGetLabel(Kref, labelName, &identityRef);CHKERRQ(ierr); ierr = DMPlexGetChart(Kref, &pRefStart, &pRefEnd);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, &unionSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(unionSection, 0, (pEnd - pStart) + (pRefEnd - pRefStart));CHKERRQ(ierr); /* count points that will go in the union */ for (p = pStart; p < pEnd; p++) { ierr = PetscSectionSetDof(unionSection, p - pStart, 1);CHKERRQ(ierr); } for (p = pRefStart; p < pRefEnd; p++) { PetscInt q, qSize; ierr = DMLabelGetValue(identityRef, p, &q);CHKERRQ(ierr); ierr = DMLabelGetStratumSize(identityRef, q, &qSize);CHKERRQ(ierr); if (qSize > 1) { ierr = PetscSectionSetDof(unionSection, p - pRefStart + (pEnd - pStart), 1);CHKERRQ(ierr); } } ierr = PetscMalloc1(pEnd - pStart + pRefEnd - pRefStart,&permvals);CHKERRQ(ierr); offset = 0; /* stratify points in the union by topological dimension */ for (d = 0; d <= dim; d++) { PetscInt cStart, cEnd, c; ierr = DMPlexGetHeightStratum(K, d, &cStart, &cEnd);CHKERRQ(ierr); for (c = cStart; c < cEnd; c++) { permvals[offset++] = c; } ierr = DMPlexGetHeightStratum(Kref, d, &cStart, &cEnd);CHKERRQ(ierr); for (c = cStart; c < cEnd; c++) { permvals[offset++] = c + (pEnd - pStart); } } ierr = ISCreateGeneral(comm, (pEnd - pStart) + (pRefEnd - pRefStart), permvals, PETSC_OWN_POINTER, &perm);CHKERRQ(ierr); ierr = PetscSectionSetPermutation(unionSection,perm);CHKERRQ(ierr); ierr = PetscSectionSetUp(unionSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(unionSection,&numUnionPoints);CHKERRQ(ierr); ierr = PetscMalloc2(numUnionPoints,&coneSizes,dim+1,&numDimPoints);CHKERRQ(ierr); /* count dimension points */ for (d = 0; d <= dim; d++) { PetscInt cStart, cOff, cOff2; ierr = DMPlexGetHeightStratum(K,d,&cStart,NULL);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff);CHKERRQ(ierr); if (d < dim) { ierr = DMPlexGetHeightStratum(K,d+1,&cStart,NULL);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection,cStart-pStart,&cOff2);CHKERRQ(ierr); } else { cOff2 = numUnionPoints; } numDimPoints[dim - d] = cOff2 - cOff; } ierr = PetscSectionCreate(comm, &unionConeSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(unionConeSection, 0, numUnionPoints);CHKERRQ(ierr); /* count the cones in the union */ for (p = pStart; p < pEnd; p++) { PetscInt dof, uOff; ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr); ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr); coneSizes[uOff] = dof; } for (p = pRefStart; p < pRefEnd; p++) { PetscInt dof, uDof, uOff; ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr); if (uDof) { ierr = PetscSectionSetDof(unionConeSection, uOff, dof);CHKERRQ(ierr); coneSizes[uOff] = dof; } } ierr = PetscSectionSetUp(unionConeSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(unionConeSection,&numCones);CHKERRQ(ierr); ierr = PetscMalloc2(numCones,&unionCones,numCones,&unionOrientations);CHKERRQ(ierr); /* write the cones in the union */ for (p = pStart; p < pEnd; p++) { PetscInt dof, uOff, c, cOff; const PetscInt *cone, *orientation; ierr = DMPlexGetConeSize(K, p, &dof);CHKERRQ(ierr); ierr = DMPlexGetCone(K, p, &cone);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(K, p, &orientation);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pStart,&uOff);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr); for (c = 0; c < dof; c++) { PetscInt e, eOff; e = cone[c]; ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr); unionCones[cOff + c] = eOff; unionOrientations[cOff + c] = orientation[c]; } } for (p = pRefStart; p < pRefEnd; p++) { PetscInt dof, uDof, uOff, c, cOff; const PetscInt *cone, *orientation; ierr = DMPlexGetConeSize(Kref, p, &dof);CHKERRQ(ierr); ierr = DMPlexGetCone(Kref, p, &cone);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(Kref, p, &orientation);CHKERRQ(ierr); ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr); if (uDof) { ierr = PetscSectionGetOffset(unionConeSection,uOff,&cOff);CHKERRQ(ierr); for (c = 0; c < dof; c++) { PetscInt e, eOff, eDof; e = cone[c]; ierr = PetscSectionGetDof(unionSection, e - pRefStart + (pEnd - pStart),&eDof);CHKERRQ(ierr); if (eDof) { ierr = PetscSectionGetOffset(unionSection, e - pRefStart + (pEnd - pStart), &eOff);CHKERRQ(ierr); } else { ierr = DMLabelGetValue(identityRef, e, &e);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, e - pStart, &eOff);CHKERRQ(ierr); } unionCones[cOff + c] = eOff; unionOrientations[cOff + c] = orientation[c]; } } } /* get the coordinates */ { PetscInt vStart, vEnd, vRefStart, vRefEnd, v, vDof, vOff; PetscSection KcoordsSec, KrefCoordsSec; Vec KcoordsVec, KrefCoordsVec; PetscScalar *Kcoords; DMGetCoordinateSection(K, &KcoordsSec);CHKERRQ(ierr); DMGetCoordinatesLocal(K, &KcoordsVec);CHKERRQ(ierr); DMGetCoordinateSection(Kref, &KrefCoordsSec);CHKERRQ(ierr); DMGetCoordinatesLocal(Kref, &KrefCoordsVec);CHKERRQ(ierr); numVerts = numDimPoints[0]; ierr = PetscMalloc1(numVerts * dim,&unionCoords);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(K,0,&vStart,&vEnd);CHKERRQ(ierr); offset = 0; for (v = vStart; v < vEnd; v++) { ierr = PetscSectionGetOffset(unionSection,v - pStart,&vOff);CHKERRQ(ierr); ierr = VecGetValuesSection(KcoordsVec, KcoordsSec, v, &Kcoords);CHKERRQ(ierr); for (d = 0; d < dim; d++) { unionCoords[offset * dim + d] = Kcoords[d]; } offset++; } ierr = DMPlexGetDepthStratum(Kref,0,&vRefStart,&vRefEnd);CHKERRQ(ierr); for (v = vRefStart; v < vRefEnd; v++) { ierr = PetscSectionGetDof(unionSection,v - pRefStart + (pEnd - pStart),&vDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection,v - pRefStart + (pEnd - pStart),&vOff);CHKERRQ(ierr); ierr = VecGetValuesSection(KrefCoordsVec, KrefCoordsSec, v, &Kcoords);CHKERRQ(ierr); if (vDof) { for (d = 0; d < dim; d++) { unionCoords[offset * dim + d] = Kcoords[d]; } offset++; } } } ierr = DMCreate(comm,ref);CHKERRQ(ierr); ierr = DMSetType(*ref,DMPLEX);CHKERRQ(ierr); ierr = DMSetDimension(*ref,dim);CHKERRQ(ierr); ierr = DMPlexCreateFromDAG(*ref,dim,numDimPoints,coneSizes,unionCones,unionOrientations,unionCoords);CHKERRQ(ierr); /* set the tree */ ierr = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(parentSection,0,numUnionPoints);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt uDof, uOff; ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr); if (uDof) { PetscSectionSetDof(parentSection,uOff,1);CHKERRQ(ierr); } } ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(parentSection,&parentSize);CHKERRQ(ierr); ierr = PetscMalloc2(parentSize,&parents,parentSize,&childIDs);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt uDof, uOff; ierr = PetscSectionGetDof(unionSection, p - pRefStart + (pEnd - pStart),&uDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, p - pRefStart + (pEnd - pStart),&uOff);CHKERRQ(ierr); if (uDof) { PetscInt pOff, parent, parentU; PetscSectionGetOffset(parentSection,uOff,&pOff);CHKERRQ(ierr); DMLabelGetValue(identityRef,p,&parent);CHKERRQ(ierr); ierr = PetscSectionGetOffset(unionSection, parent - pStart,&parentU);CHKERRQ(ierr); parents[pOff] = parentU; childIDs[pOff] = uOff; } } ierr = DMPlexSetTree_Internal(*ref,parentSection,parents,childIDs,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr); ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr); ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr); /* clean up */ ierr = PetscSectionDestroy(&unionSection);CHKERRQ(ierr); ierr = PetscSectionDestroy(&unionConeSection);CHKERRQ(ierr); ierr = ISDestroy(&perm);CHKERRQ(ierr); ierr = PetscFree(unionCoords);CHKERRQ(ierr); ierr = PetscFree2(unionCones,unionOrientations);CHKERRQ(ierr); ierr = PetscFree2(coneSizes,numDimPoints);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexCreateDefaultReferenceTree" /*@ DMPlexCreateDefaultReferenceTree - create a reference tree for isotropic hierarchical mesh refinement. Collective on comm Input Parameters: + comm - the MPI communicator . dim - the spatial dimension - simplex - Flag for simplex, otherwise use a tensor-product cell Output Parameters: . ref - the reference tree DMPlex object Level: intermediate .keywords: reference cell .seealso: DMPlexSetReferenceTree(), DMPlexGetReferenceTree() @*/ PetscErrorCode DMPlexCreateDefaultReferenceTree(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *ref) { DM_Plex *mesh; DM K, Kref; PetscInt p, pStart, pEnd; DMLabel identity; PetscErrorCode ierr; PetscFunctionBegin; #if 1 comm = PETSC_COMM_SELF; #endif /* create a reference element */ ierr = DMPlexCreateReferenceCell(comm, dim, simplex, &K);CHKERRQ(ierr); ierr = DMCreateLabel(K, "identity");CHKERRQ(ierr); ierr = DMGetLabel(K, "identity", &identity);CHKERRQ(ierr); ierr = DMPlexGetChart(K, &pStart, &pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { ierr = DMLabelSetValue(identity, p, p);CHKERRQ(ierr); } /* refine it */ ierr = DMRefine(K,comm,&Kref);CHKERRQ(ierr); /* the reference tree is the union of these two, without duplicating * points that appear in both */ ierr = DMPlexCreateReferenceTree_Union(K, Kref, "identity", ref);CHKERRQ(ierr); mesh = (DM_Plex *) (*ref)->data; mesh->getchildsymmetry = DMPlexReferenceTreeGetChildSymmetry_Default; ierr = DMDestroy(&K);CHKERRQ(ierr); ierr = DMDestroy(&Kref);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTreeSymmetrize" static PetscErrorCode DMPlexTreeSymmetrize(DM dm) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscSection childSec, pSec; PetscInt p, pSize, cSize, parMax = PETSC_MIN_INT, parMin = PETSC_MAX_INT; PetscInt *offsets, *children, pStart, pEnd; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr); ierr = PetscFree(mesh->children);CHKERRQ(ierr); pSec = mesh->parentSection; if (!pSec) PetscFunctionReturn(0); ierr = PetscSectionGetStorageSize(pSec,&pSize);CHKERRQ(ierr); for (p = 0; p < pSize; p++) { PetscInt par = mesh->parents[p]; parMax = PetscMax(parMax,par+1); parMin = PetscMin(parMin,par); } if (parMin > parMax) { parMin = -1; parMax = -1; } ierr = PetscSectionCreate(PetscObjectComm((PetscObject)pSec),&childSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(childSec,parMin,parMax);CHKERRQ(ierr); for (p = 0; p < pSize; p++) { PetscInt par = mesh->parents[p]; ierr = PetscSectionAddDof(childSec,par,1);CHKERRQ(ierr); } ierr = PetscSectionSetUp(childSec);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(childSec,&cSize);CHKERRQ(ierr); ierr = PetscMalloc1(cSize,&children);CHKERRQ(ierr); ierr = PetscCalloc1(parMax-parMin,&offsets);CHKERRQ(ierr); ierr = PetscSectionGetChart(pSec,&pStart,&pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { PetscInt dof, off, i; ierr = PetscSectionGetDof(pSec,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(pSec,p,&off);CHKERRQ(ierr); for (i = 0; i < dof; i++) { PetscInt par = mesh->parents[off + i], cOff; ierr = PetscSectionGetOffset(childSec,par,&cOff);CHKERRQ(ierr); children[cOff + offsets[par-parMin]++] = p; } } mesh->childSection = childSec; mesh->children = children; ierr = PetscFree(offsets);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "AnchorsFlatten" static PetscErrorCode AnchorsFlatten (PetscSection section, IS is, PetscSection *sectionNew, IS *isNew) { PetscInt pStart, pEnd, size, sizeNew, i, p, *valsNew = NULL; const PetscInt *vals; PetscSection secNew; PetscBool anyNew, globalAnyNew; PetscBool compress; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr); ierr = ISGetLocalSize(is,&size);CHKERRQ(ierr); ierr = ISGetIndices(is,&vals);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secNew);CHKERRQ(ierr); ierr = PetscSectionSetChart(secNew,pStart,pEnd);CHKERRQ(ierr); for (i = 0; i < size; i++) { PetscInt dof; p = vals[i]; if (p < pStart || p >= pEnd) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); if (dof) break; } if (i == size) { ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr); anyNew = PETSC_FALSE; compress = PETSC_FALSE; sizeNew = 0; } else { anyNew = PETSC_TRUE; for (p = pStart; p < pEnd; p++) { PetscInt dof, off; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); for (i = 0; i < dof; i++) { PetscInt q = vals[off + i], qDof = 0; if (q >= pStart && q < pEnd) { ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr); } if (qDof) { ierr = PetscSectionAddDof(secNew, p, qDof);CHKERRQ(ierr); } else { ierr = PetscSectionAddDof(secNew, p, 1);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(secNew);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(secNew,&sizeNew);CHKERRQ(ierr); ierr = PetscMalloc1(sizeNew,&valsNew);CHKERRQ(ierr); compress = PETSC_FALSE; for (p = pStart; p < pEnd; p++) { PetscInt dof, off, count, offNew, dofNew; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetDof(secNew, p, &dofNew);CHKERRQ(ierr); ierr = PetscSectionGetOffset(secNew, p, &offNew);CHKERRQ(ierr); count = 0; for (i = 0; i < dof; i++) { PetscInt q = vals[off + i], qDof = 0, qOff = 0, j; if (q >= pStart && q < pEnd) { ierr = PetscSectionGetDof(section, q, &qDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, q, &qOff);CHKERRQ(ierr); } if (qDof) { PetscInt oldCount = count; for (j = 0; j < qDof; j++) { PetscInt k, r = vals[qOff + j]; for (k = 0; k < oldCount; k++) { if (valsNew[offNew + k] == r) { break; } } if (k == oldCount) { valsNew[offNew + count++] = r; } } } else { PetscInt k, oldCount = count; for (k = 0; k < oldCount; k++) { if (valsNew[offNew + k] == q) { break; } } if (k == oldCount) { valsNew[offNew + count++] = q; } } } if (count < dofNew) { ierr = PetscSectionSetDof(secNew, p, count);CHKERRQ(ierr); compress = PETSC_TRUE; } } } ierr = ISRestoreIndices(is,&vals);CHKERRQ(ierr); ierr = MPIU_Allreduce(&anyNew,&globalAnyNew,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr); if (!globalAnyNew) { ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr); *sectionNew = NULL; *isNew = NULL; } else { PetscBool globalCompress; ierr = MPIU_Allreduce(&compress,&globalCompress,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)secNew));CHKERRQ(ierr); if (compress) { PetscSection secComp; PetscInt *valsComp = NULL; ierr = PetscSectionCreate(PetscObjectComm((PetscObject)section),&secComp);CHKERRQ(ierr); ierr = PetscSectionSetChart(secComp,pStart,pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { PetscInt dof; ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr); ierr = PetscSectionSetDof(secComp, p, dof);CHKERRQ(ierr); } ierr = PetscSectionSetUp(secComp);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(secComp,&sizeNew);CHKERRQ(ierr); ierr = PetscMalloc1(sizeNew,&valsComp);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { PetscInt dof, off, offNew, j; ierr = PetscSectionGetDof(secNew, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(secNew, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(secComp, p, &offNew);CHKERRQ(ierr); for (j = 0; j < dof; j++) { valsComp[offNew + j] = valsNew[off + j]; } } ierr = PetscSectionDestroy(&secNew);CHKERRQ(ierr); secNew = secComp; ierr = PetscFree(valsNew);CHKERRQ(ierr); valsNew = valsComp; } ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),sizeNew,valsNew,PETSC_OWN_POINTER,isNew);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexCreateAnchors_Tree" static PetscErrorCode DMPlexCreateAnchors_Tree(DM dm) { PetscInt p, pStart, pEnd, *anchors, size; PetscInt aMin = PETSC_MAX_INT, aMax = PETSC_MIN_INT; PetscSection aSec; DMLabel canonLabel; IS aIS; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = DMGetLabel(dm,"canonical",&canonLabel);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { PetscInt parent; if (canonLabel) { PetscInt canon; ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr); if (p != canon) continue; } ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr); if (parent != p) { aMin = PetscMin(aMin,p); aMax = PetscMax(aMax,p+1); } } if (aMin > aMax) { aMin = -1; aMax = -1; } ierr = PetscSectionCreate(PETSC_COMM_SELF,&aSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(aSec,aMin,aMax);CHKERRQ(ierr); for (p = aMin; p < aMax; p++) { PetscInt parent, ancestor = p; if (canonLabel) { PetscInt canon; ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr); if (p != canon) continue; } ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr); while (parent != ancestor) { ancestor = parent; ierr = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr); } if (ancestor != p) { PetscInt closureSize, *closure = NULL; ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); ierr = PetscSectionSetDof(aSec,p,closureSize);CHKERRQ(ierr); ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); } } ierr = PetscSectionSetUp(aSec);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(aSec,&size);CHKERRQ(ierr); ierr = PetscMalloc1(size,&anchors);CHKERRQ(ierr); for (p = aMin; p < aMax; p++) { PetscInt parent, ancestor = p; if (canonLabel) { PetscInt canon; ierr = DMLabelGetValue(canonLabel,p,&canon);CHKERRQ(ierr); if (p != canon) continue; } ierr = DMPlexGetTreeParent(dm,p,&parent,NULL);CHKERRQ(ierr); while (parent != ancestor) { ancestor = parent; ierr = DMPlexGetTreeParent(dm,ancestor,&parent,NULL);CHKERRQ(ierr); } if (ancestor != p) { PetscInt j, closureSize, *closure = NULL, aOff; ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr); ierr = DMPlexGetTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (j = 0; j < closureSize; j++) { anchors[aOff + j] = closure[2*j]; } ierr = DMPlexRestoreTransitiveClosure(dm,ancestor,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); } } ierr = ISCreateGeneral(PETSC_COMM_SELF,size,anchors,PETSC_OWN_POINTER,&aIS);CHKERRQ(ierr); { PetscSection aSecNew = aSec; IS aISNew = aIS; ierr = PetscObjectReference((PetscObject)aSec);CHKERRQ(ierr); ierr = PetscObjectReference((PetscObject)aIS);CHKERRQ(ierr); while (aSecNew) { ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr); ierr = ISDestroy(&aIS);CHKERRQ(ierr); aSec = aSecNew; aIS = aISNew; aSecNew = NULL; aISNew = NULL; ierr = AnchorsFlatten(aSec,aIS,&aSecNew,&aISNew);CHKERRQ(ierr); } } ierr = DMPlexSetAnchors(dm,aSec,aIS);CHKERRQ(ierr); ierr = PetscSectionDestroy(&aSec);CHKERRQ(ierr); ierr = ISDestroy(&aIS);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetTrueSupportSize" static PetscErrorCode DMPlexGetTrueSupportSize(DM dm,PetscInt p,PetscInt *dof,PetscInt *numTrueSupp) { PetscErrorCode ierr; PetscFunctionBegin; if (numTrueSupp[p] == -1) { PetscInt i, alldof; const PetscInt *supp; PetscInt count = 0; ierr = DMPlexGetSupportSize(dm,p,&alldof);CHKERRQ(ierr); ierr = DMPlexGetSupport(dm,p,&supp);CHKERRQ(ierr); for (i = 0; i < alldof; i++) { PetscInt q = supp[i], numCones, j; const PetscInt *cone; ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr); for (j = 0; j < numCones; j++) { if (cone[j] == p) break; } if (j < numCones) count++; } numTrueSupp[p] = count; } *dof = numTrueSupp[p]; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTreeExchangeSupports" static PetscErrorCode DMPlexTreeExchangeSupports(DM dm) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscSection newSupportSection; PetscInt newSize, *newSupports, pStart, pEnd, p, d, depth; PetscInt *numTrueSupp; PetscInt *offsets; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); /* symmetrize the hierarchy */ ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)(mesh->supportSection)),&newSupportSection);CHKERRQ(ierr); ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = PetscSectionSetChart(newSupportSection,pStart,pEnd);CHKERRQ(ierr); ierr = PetscCalloc1(pEnd,&offsets);CHKERRQ(ierr); ierr = PetscMalloc1(pEnd,&numTrueSupp);CHKERRQ(ierr); for (p = 0; p < pEnd; p++) numTrueSupp[p] = -1; /* if a point is in the (true) support of q, it should be in the support of * parent(q) */ for (d = 0; d <= depth; d++) { ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, q, qdof, parent; ierr = DMPlexGetTrueSupportSize(dm,p,&dof,numTrueSupp);CHKERRQ(ierr); ierr = PetscSectionAddDof(newSupportSection, p, dof);CHKERRQ(ierr); q = p; ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr); while (parent != q && parent >= pStart && parent < pEnd) { q = parent; ierr = DMPlexGetTrueSupportSize(dm,q,&qdof,numTrueSupp);CHKERRQ(ierr); ierr = PetscSectionAddDof(newSupportSection,p,qdof);CHKERRQ(ierr); ierr = PetscSectionAddDof(newSupportSection,q,dof);CHKERRQ(ierr); ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(newSupportSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(newSupportSection,&newSize);CHKERRQ(ierr); ierr = PetscMalloc1(newSize,&newSupports);CHKERRQ(ierr); for (d = 0; d <= depth; d++) { ierr = DMPlexGetHeightStratum(dm,d,&pStart,&pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { PetscInt dof, off, q, qdof, qoff, newDof, newOff, newqOff, i, parent; ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetDof(newSupportSection, p, &newDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(newSupportSection, p, &newOff);CHKERRQ(ierr); for (i = 0; i < dof; i++) { PetscInt numCones, j; const PetscInt *cone; PetscInt q = mesh->supports[off + i]; ierr = DMPlexGetConeSize(dm,q,&numCones);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,q,&cone);CHKERRQ(ierr); for (j = 0; j < numCones; j++) { if (cone[j] == p) break; } if (j < numCones) newSupports[newOff+offsets[p]++] = q; } mesh->maxSupportSize = PetscMax(mesh->maxSupportSize,newDof); q = p; ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr); while (parent != q && parent >= pStart && parent < pEnd) { q = parent; ierr = PetscSectionGetDof(mesh->supportSection, q, &qdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(mesh->supportSection, q, &qoff);CHKERRQ(ierr); ierr = PetscSectionGetOffset(newSupportSection, q, &newqOff);CHKERRQ(ierr); for (i = 0; i < qdof; i++) { PetscInt numCones, j; const PetscInt *cone; PetscInt r = mesh->supports[qoff + i]; ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr); for (j = 0; j < numCones; j++) { if (cone[j] == q) break; } if (j < numCones) newSupports[newOff+offsets[p]++] = r; } for (i = 0; i < dof; i++) { PetscInt numCones, j; const PetscInt *cone; PetscInt r = mesh->supports[off + i]; ierr = DMPlexGetConeSize(dm,r,&numCones);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,r,&cone);CHKERRQ(ierr); for (j = 0; j < numCones; j++) { if (cone[j] == p) break; } if (j < numCones) newSupports[newqOff+offsets[q]++] = r; } ierr = DMPlexGetTreeParent(dm,q,&parent,NULL);CHKERRQ(ierr); } } } ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); mesh->supportSection = newSupportSection; ierr = PetscFree(mesh->supports);CHKERRQ(ierr); mesh->supports = newSupports; ierr = PetscFree(offsets);CHKERRQ(ierr); ierr = PetscFree(numTrueSupp);CHKERRQ(ierr); PetscFunctionReturn(0); } static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM,PetscSection,PetscSection,Mat); static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM,PetscSection,PetscSection,Mat); #undef __FUNCT__ #define __FUNCT__ "DMPlexSetTree_Internal" static PetscErrorCode DMPlexSetTree_Internal(DM dm, PetscSection parentSection, PetscInt *parents, PetscInt *childIDs, PetscBool computeCanonical, PetscBool exchangeSupports) { DM_Plex *mesh = (DM_Plex *)dm->data; DM refTree; PetscInt size; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(parentSection, PETSC_SECTION_CLASSID, 2); ierr = PetscObjectReference((PetscObject)parentSection);CHKERRQ(ierr); ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr); mesh->parentSection = parentSection; ierr = PetscSectionGetStorageSize(parentSection,&size);CHKERRQ(ierr); if (parents != mesh->parents) { ierr = PetscFree(mesh->parents);CHKERRQ(ierr); ierr = PetscMalloc1(size,&mesh->parents);CHKERRQ(ierr); ierr = PetscMemcpy(mesh->parents, parents, size * sizeof(*parents));CHKERRQ(ierr); } if (childIDs != mesh->childIDs) { ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr); ierr = PetscMalloc1(size,&mesh->childIDs);CHKERRQ(ierr); ierr = PetscMemcpy(mesh->childIDs, childIDs, size * sizeof(*childIDs));CHKERRQ(ierr); } ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr); if (refTree) { DMLabel canonLabel; ierr = DMGetLabel(refTree,"canonical",&canonLabel);CHKERRQ(ierr); if (canonLabel) { PetscInt i; for (i = 0; i < size; i++) { PetscInt canon; ierr = DMLabelGetValue(canonLabel, mesh->childIDs[i], &canon);CHKERRQ(ierr); if (canon >= 0) { mesh->childIDs[i] = canon; } } } mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_FromReference; } else { mesh->computeanchormatrix = DMPlexComputeAnchorMatrix_Tree_Direct; } ierr = DMPlexTreeSymmetrize(dm);CHKERRQ(ierr); if (computeCanonical) { PetscInt d, dim; /* add the canonical label */ ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); ierr = DMCreateLabel(dm,"canonical");CHKERRQ(ierr); for (d = 0; d <= dim; d++) { PetscInt p, dStart, dEnd, canon = -1, cNumChildren; const PetscInt *cChildren; ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr); for (p = dStart; p < dEnd; p++) { ierr = DMPlexGetTreeChildren(dm,p,&cNumChildren,&cChildren);CHKERRQ(ierr); if (cNumChildren) { canon = p; break; } } if (canon == -1) continue; for (p = dStart; p < dEnd; p++) { PetscInt numChildren, i; const PetscInt *children; ierr = DMPlexGetTreeChildren(dm,p,&numChildren,&children);CHKERRQ(ierr); if (numChildren) { if (numChildren != cNumChildren) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"All parent points in a stratum should have the same number of children: %d != %d", numChildren, cNumChildren); ierr = DMSetLabelValue(dm,"canonical",p,canon);CHKERRQ(ierr); for (i = 0; i < numChildren; i++) { ierr = DMSetLabelValue(dm,"canonical",children[i],cChildren[i]);CHKERRQ(ierr); } } } } } if (exchangeSupports) { ierr = DMPlexTreeExchangeSupports(dm);CHKERRQ(ierr); } mesh->createanchors = DMPlexCreateAnchors_Tree; /* reset anchors */ ierr = DMPlexSetAnchors(dm,NULL,NULL);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexSetTree" /*@ DMPlexSetTree - set the tree that describes the hierarchy of non-conforming mesh points. This routine also creates the point-to-point constraints determined by the tree: a point is constained to the points in the closure of its tree root. Collective on dm Input Parameters: + dm - the DMPlex object . parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section offset indexes the parent and childID list; the reference count of parentSection is incremented . parents - a list of the point parents; copied, can be destroyed - childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then the child corresponds to the point in the reference tree with index childIDs; copied, can be destroyed Level: intermediate .seealso: DMPlexGetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren() @*/ PetscErrorCode DMPlexSetTree(DM dm, PetscSection parentSection, PetscInt parents[], PetscInt childIDs[]) { PetscErrorCode ierr; PetscFunctionBegin; ierr = DMPlexSetTree_Internal(dm,parentSection,parents,childIDs,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetTree" /*@ DMPlexGetTree - get the tree that describes the hierarchy of non-conforming mesh points. Collective on dm Input Parameters: . dm - the DMPlex object Output Parameters: + parentSection - a section describing the tree: a point has a parent if it has 1 dof in the section; the section offset indexes the parent and childID list . parents - a list of the point parents . childIDs - identifies the relationship of the child point to the parent point; if there is a reference tree, then the child corresponds to the point in the reference tree with index childID . childSection - the inverse of the parent section - children - a list of the point children Level: intermediate .seealso: DMPlexSetTree(), DMPlexSetReferenceTree(), DMPlexSetAnchors(), DMPlexGetTreeParent(), DMPlexGetTreeChildren() @*/ PetscErrorCode DMPlexGetTree(DM dm, PetscSection *parentSection, PetscInt *parents[], PetscInt *childIDs[], PetscSection *childSection, PetscInt *children[]) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); if (parentSection) *parentSection = mesh->parentSection; if (parents) *parents = mesh->parents; if (childIDs) *childIDs = mesh->childIDs; if (childSection) *childSection = mesh->childSection; if (children) *children = mesh->children; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetTreeParent" /*@ DMPlexGetTreeParent - get the parent of a point in the tree describing the point hierarchy (not the Sieve DAG) Input Parameters: + dm - the DMPlex object - point - the query point Output Parameters: + parent - if not NULL, set to the parent of the point, or the point itself if the point does not have a parent - childID - if not NULL, set to the child ID of the point with respect to its parent, or 0 if the point does not have a parent Level: intermediate .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeChildren() @*/ PetscErrorCode DMPlexGetTreeParent(DM dm, PetscInt point, PetscInt *parent, PetscInt *childID) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscSection pSec; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); pSec = mesh->parentSection; if (pSec && point >= pSec->pStart && point < pSec->pEnd) { PetscInt dof; ierr = PetscSectionGetDof (pSec, point, &dof);CHKERRQ(ierr); if (dof) { PetscInt off; ierr = PetscSectionGetOffset (pSec, point, &off);CHKERRQ(ierr); if (parent) *parent = mesh->parents[off]; if (childID) *childID = mesh->childIDs[off]; PetscFunctionReturn(0); } } if (parent) { *parent = point; } if (childID) { *childID = 0; } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetTreeChildren" /*@C DMPlexGetTreeChildren - get the children of a point in the tree describing the point hierarchy (not the Sieve DAG) Input Parameters: + dm - the DMPlex object - point - the query point Output Parameters: + numChildren - if not NULL, set to the number of children - children - if not NULL, set to a list children, or set to NULL if the point has no children Level: intermediate Fortran Notes: Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. .seealso: DMPlexSetTree(), DMPlexGetTree(), DMPlexGetTreeParent() @*/ PetscErrorCode DMPlexGetTreeChildren(DM dm, PetscInt point, PetscInt *numChildren, const PetscInt *children[]) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscSection childSec; PetscInt dof = 0; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); childSec = mesh->childSection; if (childSec && point >= childSec->pStart && point < childSec->pEnd) { ierr = PetscSectionGetDof (childSec, point, &dof);CHKERRQ(ierr); } if (numChildren) *numChildren = dof; if (children) { if (dof) { PetscInt off; ierr = PetscSectionGetOffset (childSec, point, &off);CHKERRQ(ierr); *children = &mesh->children[off]; } else { *children = NULL; } } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_Direct" static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_Direct(DM dm, PetscSection section, PetscSection cSec, Mat cMat) { PetscDS ds; PetscInt spdim; PetscInt numFields, f, c, cStart, cEnd, pStart, pEnd, conStart, conEnd; const PetscInt *anchors; PetscSection aSec; PetscReal *v0, *v0parent, *vtmp, *J, *Jparent, *invJparent, detJ, detJparent; IS aIS; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = DMGetDS(dm,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); ierr = PetscSectionGetChart(cSec,&conStart,&conEnd);CHKERRQ(ierr); ierr = DMGetDimension(dm,&spdim);CHKERRQ(ierr); ierr = PetscMalloc6(spdim,&v0,spdim,&v0parent,spdim,&vtmp,spdim*spdim,&J,spdim*spdim,&Jparent,spdim*spdim,&invJparent);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscObject disc; PetscFE fe = NULL; PetscFV fv = NULL; PetscClassId id; PetscDualSpace space; PetscInt i, j, k, nPoints, offset; PetscInt fSize, fComp; PetscReal *B = NULL; PetscReal *weights, *pointsRef, *pointsReal; Mat Amat, Bmat, Xmat; ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr); ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); if (id == PETSCFE_CLASSID) { fe = (PetscFE) disc; ierr = PetscFEGetDualSpace(fe,&space);CHKERRQ(ierr); ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr); ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr); } else if (id == PETSCFV_CLASSID) { fv = (PetscFV) disc; ierr = PetscFVGetDualSpace(fv,&space);CHKERRQ(ierr); ierr = PetscDualSpaceGetDimension(space,&fSize);CHKERRQ(ierr); ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr); } else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id); ierr = MatCreate(PETSC_COMM_SELF,&Amat);CHKERRQ(ierr); ierr = MatSetSizes(Amat,fSize,fSize,fSize,fSize);CHKERRQ(ierr); ierr = MatSetType(Amat,MATSEQDENSE);CHKERRQ(ierr); ierr = MatSetUp(Amat);CHKERRQ(ierr); ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Bmat);CHKERRQ(ierr); ierr = MatDuplicate(Amat,MAT_DO_NOT_COPY_VALUES,&Xmat);CHKERRQ(ierr); nPoints = 0; for (i = 0; i < fSize; i++) { PetscInt qPoints; PetscQuadrature quad; ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr); ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr); nPoints += qPoints; } ierr = PetscMalloc3(nPoints,&weights,spdim*nPoints,&pointsRef,spdim*nPoints,&pointsReal);CHKERRQ(ierr); offset = 0; for (i = 0; i < fSize; i++) { PetscInt qPoints; const PetscReal *p, *w; PetscQuadrature quad; ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr); ierr = PetscQuadratureGetData(quad,NULL,&qPoints,&p,&w);CHKERRQ(ierr); ierr = PetscMemcpy(weights+offset,w,qPoints*sizeof(*w));CHKERRQ(ierr); ierr = PetscMemcpy(pointsRef+spdim*offset,p,spdim*qPoints*sizeof(*p));CHKERRQ(ierr); offset += qPoints; } if (id == PETSCFE_CLASSID) { ierr = PetscFEGetTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr); } else { ierr = PetscFVGetTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr); } offset = 0; for (i = 0; i < fSize; i++) { PetscInt qPoints; PetscQuadrature quad; ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr); ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr); for (j = 0; j < fSize; j++) { PetscScalar val = 0.; for (k = 0; k < qPoints; k++) { val += B[((offset + k) * fSize + j) * fComp] * weights[k]; } ierr = MatSetValue(Amat,i,j,val,INSERT_VALUES);CHKERRQ(ierr); } offset += qPoints; } if (id == PETSCFE_CLASSID) { ierr = PetscFERestoreTabulation(fe,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr); } else { ierr = PetscFVRestoreTabulation(fv,nPoints,pointsRef,&B,NULL,NULL);CHKERRQ(ierr); } ierr = MatAssemblyBegin(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(Amat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatLUFactor(Amat,NULL,NULL,NULL);CHKERRQ(ierr); for (c = cStart; c < cEnd; c++) { PetscInt parent; PetscInt closureSize, closureSizeP, *closure = NULL, *closureP = NULL; PetscInt *childOffsets, *parentOffsets; ierr = DMPlexGetTreeParent(dm,c,&parent,NULL);CHKERRQ(ierr); if (parent == c) continue; ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (i = 0; i < closureSize; i++) { PetscInt p = closure[2*i]; PetscInt conDof; if (p < conStart || p >= conEnd) continue; if (numFields > 1) { ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr); } if (conDof) break; } if (i == closureSize) { ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); continue; } ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr); ierr = DMPlexComputeCellGeometryFEM(dm, parent, NULL, v0parent, Jparent, invJparent, &detJparent);CHKERRQ(ierr); for (i = 0; i < nPoints; i++) { CoordinatesRefToReal(spdim, spdim, v0, J, &pointsRef[i*spdim],vtmp);CHKERRQ(ierr); CoordinatesRealToRef(spdim, spdim, v0parent, invJparent, vtmp, &pointsReal[i*spdim]);CHKERRQ(ierr); } if (id == PETSCFE_CLASSID) { ierr = PetscFEGetTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr); } else { ierr = PetscFVGetTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr); } offset = 0; for (i = 0; i < fSize; i++) { PetscInt qPoints; PetscQuadrature quad; ierr = PetscDualSpaceGetFunctional(space,i,&quad);CHKERRQ(ierr); ierr = PetscQuadratureGetData(quad,NULL,&qPoints,NULL,NULL);CHKERRQ(ierr); for (j = 0; j < fSize; j++) { PetscScalar val = 0.; for (k = 0; k < qPoints; k++) { val += B[((offset + k) * fSize + j) * fComp] * weights[k]; } MatSetValue(Bmat,i,j,val,INSERT_VALUES);CHKERRQ(ierr); } offset += qPoints; } if (id == PETSCFE_CLASSID) { ierr = PetscFERestoreTabulation(fe,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr); } else { ierr = PetscFVRestoreTabulation(fv,nPoints,pointsReal,&B,NULL,NULL);CHKERRQ(ierr); } ierr = MatAssemblyBegin(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(Bmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatMatSolve(Amat,Bmat,Xmat);CHKERRQ(ierr); ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr); ierr = PetscMalloc2(closureSize+1,&childOffsets,closureSizeP+1,&parentOffsets);CHKERRQ(ierr); childOffsets[0] = 0; for (i = 0; i < closureSize; i++) { PetscInt p = closure[2*i]; PetscInt dof; if (numFields > 1) { ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); } childOffsets[i+1]=childOffsets[i]+dof / fComp; } parentOffsets[0] = 0; for (i = 0; i < closureSizeP; i++) { PetscInt p = closureP[2*i]; PetscInt dof; if (numFields > 1) { ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); } parentOffsets[i+1]=parentOffsets[i]+dof / fComp; } for (i = 0; i < closureSize; i++) { PetscInt conDof, conOff, aDof, aOff; PetscInt p = closure[2*i]; PetscInt o = closure[2*i+1]; if (p < conStart || p >= conEnd) continue; if (numFields > 1) { ierr = PetscSectionGetFieldDof(cSec,p,f,&conDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(cSec,p,f,&conOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(cSec,p,&conDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(cSec,p,&conOff);CHKERRQ(ierr); } if (!conDof) continue; ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr); for (k = 0; k < aDof; k++) { PetscInt a = anchors[aOff + k]; PetscInt aSecDof, aSecOff; if (numFields > 1) { ierr = PetscSectionGetFieldDof(section,a,f,&aSecDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(section,a,f,&aSecOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(section,a,&aSecDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section,a,&aSecOff);CHKERRQ(ierr); } if (!aSecDof) continue; for (j = 0; j < closureSizeP; j++) { PetscInt q = closureP[2*j]; PetscInt oq = closureP[2*j+1]; if (q == a) { PetscInt r, s, t; for (r = childOffsets[i]; r < childOffsets[i+1]; r++) { for (s = parentOffsets[j]; s < parentOffsets[j+1]; s++) { PetscScalar val; PetscInt insertCol, insertRow; ierr = MatGetValue(Xmat,r,s,&val);CHKERRQ(ierr); if (o >= 0) { insertRow = conOff + fComp * (r - childOffsets[i]); } else { insertRow = conOff + fComp * (childOffsets[i + 1] - 1 - r); } if (oq >= 0) { insertCol = aSecOff + fComp * (s - parentOffsets[j]); } else { insertCol = aSecOff + fComp * (parentOffsets[j + 1] - 1 - s); } for (t = 0; t < fComp; t++) { ierr = MatSetValue(cMat,insertRow + t,insertCol + t,val,INSERT_VALUES);CHKERRQ(ierr); } } } } } } } ierr = PetscFree2(childOffsets,parentOffsets);CHKERRQ(ierr); ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSizeP,&closureP);CHKERRQ(ierr); } ierr = MatDestroy(&Amat);CHKERRQ(ierr); ierr = MatDestroy(&Bmat);CHKERRQ(ierr); ierr = MatDestroy(&Xmat);CHKERRQ(ierr); ierr = PetscFree3(weights,pointsRef,pointsReal);CHKERRQ(ierr); } ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJparent);CHKERRQ(ierr); ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices" static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) { Mat refCmat; PetscDS ds; PetscInt numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof, maxAnDof, **refPointFieldN; PetscScalar ***refPointFieldMats; PetscSection refConSec, refAnSec, refSection; IS refAnIS; const PetscInt *refAnchors; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr); ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr); ierr = ISGetIndices(refAnIS,&refAnchors);CHKERRQ(ierr); ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr); ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldN);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof*maxAnDof,&cols);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt parent, closureSize, *closure = NULL, pDof; ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr); ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr); if (!pDof || parent == p) continue; ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr); ierr = PetscCalloc1(numFields,&refPointFieldN[p-pRefStart]);CHKERRQ(ierr); ierr = DMPlexGetTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscInt cDof, cOff, numCols, r, i, fComp; PetscObject disc; PetscClassId id; PetscFE fe = NULL; PetscFV fv = NULL; ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr); ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); if (id == PETSCFE_CLASSID) { fe = (PetscFE) disc; ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr); } else if (id == PETSCFV_CLASSID) { fv = (PetscFV) disc; ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr); } else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id); if (numFields > 1) { ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr); } for (r = 0; r < cDof; r++) { rows[r] = cOff + r; } numCols = 0; for (i = 0; i < closureSize; i++) { PetscInt q = closure[2*i]; PetscInt o = closure[2*i+1]; PetscInt aDof, aOff, j; if (numFields > 1) { ierr = PetscSectionGetFieldDof(refSection,q,f,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(refSection,q,f,&aOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refSection,q,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(refSection,q,&aOff);CHKERRQ(ierr); } for (j = 0; j < aDof; j++) { PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp); PetscInt comp = (j % fComp); cols[numCols++] = aOff + node * fComp + comp; } } refPointFieldN[p-pRefStart][f] = numCols; ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr); ierr = MatGetValues(refCmat,cDof,rows,numCols,cols,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr); } ierr = DMPlexRestoreTransitiveClosure(refTree,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); } *childrenMats = refPointFieldMats; *childrenN = refPointFieldN; ierr = ISRestoreIndices(refAnIS,&refAnchors);CHKERRQ(ierr); ierr = PetscFree(rows);CHKERRQ(ierr); ierr = PetscFree(cols);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices" static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices(DM refTree, PetscScalar ****childrenMats, PetscInt ***childrenN) { PetscDS ds; PetscInt **refPointFieldN; PetscScalar ***refPointFieldMats; PetscInt numFields, pRefStart, pRefEnd, p, f; PetscSection refConSec; PetscErrorCode ierr; PetscFunctionBegin; refPointFieldN = *childrenN; *childrenN = NULL; refPointFieldMats = *childrenMats; *childrenMats = NULL; ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt parent, pDof; ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr); ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr); if (!pDof || parent == p) continue; for (f = 0; f < numFields; f++) { PetscInt cDof; if (numFields > 1) { ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr); ierr = PetscFree(refPointFieldN[p - pRefStart]);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr); ierr = PetscFree(refPointFieldN);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexComputeAnchorMatrix_Tree_FromReference" static PetscErrorCode DMPlexComputeAnchorMatrix_Tree_FromReference(DM dm, PetscSection section, PetscSection conSec, Mat cMat) { DM refTree; PetscDS ds; Mat refCmat; PetscInt numFields, f, pRefStart, pRefEnd, p, maxDof, maxAnDof, *perm, *iperm, pStart, pEnd, conStart, conEnd, **refPointFieldN; PetscScalar ***refPointFieldMats, *pointWork; PetscSection refConSec, refAnSec, anSec; IS refAnIS, anIS; const PetscInt *anchors; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); ierr = DMGetDS(dm,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr); ierr = DMSetDS(refTree,ds);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,&refCmat);CHKERRQ(ierr); ierr = DMPlexGetAnchors(refTree,&refAnSec,&refAnIS);CHKERRQ(ierr); ierr = DMPlexGetAnchors(dm,&anSec,&anIS);CHKERRQ(ierr); ierr = ISGetIndices(anIS,&anchors);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = PetscSectionGetChart(conSec,&conStart,&conEnd);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refAnSec,&maxAnDof);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof*maxDof*maxAnDof,&pointWork);CHKERRQ(ierr); /* step 1: get submats for every constrained point in the reference tree */ ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); /* step 2: compute the preorder */ ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = PetscMalloc2(pEnd-pStart,&perm,pEnd-pStart,&iperm);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { perm[p - pStart] = p; iperm[p - pStart] = p-pStart; } for (p = 0; p < pEnd - pStart;) { PetscInt point = perm[p]; PetscInt parent; ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr); if (parent == point) { p++; } else { PetscInt size, closureSize, *closure = NULL, i; ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (i = 0; i < closureSize; i++) { PetscInt q = closure[2*i]; if (iperm[q-pStart] > iperm[point-pStart]) { /* swap */ perm[p] = q; perm[iperm[q-pStart]] = point; iperm[point-pStart] = iperm[q-pStart]; iperm[q-pStart] = p; break; } } size = closureSize; ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); if (i == size) { p++; } } } /* step 3: fill the constraint matrix */ /* we are going to use a preorder progressive fill strategy. Mat doesn't * allow progressive fill without assembly, so we are going to set up the * values outside of the Mat first. */ { PetscInt nRows, row, nnz; PetscBool done; const PetscInt *ia, *ja; PetscScalar *vals; ierr = MatGetRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr); if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not get RowIJ of constraint matrix"); nnz = ia[nRows]; /* malloc and then zero rows right before we fill them: this way valgrind * can tell if we are doing progressive fill in the wrong order */ ierr = PetscMalloc1(nnz,&vals);CHKERRQ(ierr); for (p = 0; p < pEnd - pStart; p++) { PetscInt parent, childid, closureSize, *closure = NULL; PetscInt point = perm[p], pointDof; ierr = DMPlexGetTreeParent(dm,point,&parent,&childid);CHKERRQ(ierr); if ((point < conStart) || (point >= conEnd) || (parent == point)) continue; ierr = PetscSectionGetDof(conSec,point,&pointDof);CHKERRQ(ierr); if (!pointDof) continue; ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscInt cDof, cOff, numCols, numFillCols, i, r, fComp = -1, matOffset, offset; PetscScalar *pointMat; PetscObject disc; PetscClassId id; PetscFE fe = NULL; PetscFV fv = NULL; ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr); ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); if (id == PETSCFE_CLASSID) { fe = (PetscFE) disc; ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr); } else if (id == PETSCFV_CLASSID) { fv = (PetscFV) disc; ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr); } else { SETERRQ(PetscObjectComm((PetscObject)disc),PETSC_ERR_SUP,"Unsupported discretization"); } if (numFields > 1) { ierr = PetscSectionGetFieldDof(conSec,point,f,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(conSec,point,f,&cOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(conSec,point,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(conSec,point,&cOff);CHKERRQ(ierr); } if (!cDof) continue; /* make sure that every row for this point is the same size */ #if defined(PETSC_USE_DEBUG) for (r = 0; r < cDof; r++) { if (cDof > 1 && r) { if ((ia[cOff+r+1]-ia[cOff+r]) != (ia[cOff+r]-ia[cOff+r-1])) SETERRQ2(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])); } } #endif /* zero rows */ for (i = ia[cOff] ; i< ia[cOff+cDof];i++) { vals[i] = 0.; } matOffset = ia[cOff]; numFillCols = ia[cOff+1] - matOffset; pointMat = refPointFieldMats[childid-pRefStart][f]; numCols = refPointFieldN[childid-pRefStart][f]; offset = 0; for (i = 0; i < closureSize; i++) { PetscInt q = closure[2*i]; PetscInt o = closure[2*i+1]; PetscInt aDof, aOff, j, k, qConDof, qConOff; qConDof = qConOff = 0; if (numFields > 1) { ierr = PetscSectionGetFieldDof(section,q,f,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(section,q,f,&aOff);CHKERRQ(ierr); if (q >= conStart && q < conEnd) { ierr = PetscSectionGetFieldDof(conSec,q,f,&qConDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(conSec,q,f,&qConOff);CHKERRQ(ierr); } } else { ierr = PetscSectionGetDof(section,q,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section,q,&aOff);CHKERRQ(ierr); if (q >= conStart && q < conEnd) { ierr = PetscSectionGetDof(conSec,q,&qConDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(conSec,q,&qConOff);CHKERRQ(ierr); } } if (!aDof) continue; if (qConDof) { /* this point has anchors: its rows of the matrix should already * be filled, thanks to preordering */ /* first multiply into pointWork, then set in matrix */ PetscInt aMatOffset = ia[qConOff]; PetscInt aNumFillCols = ia[qConOff + 1] - aMatOffset; for (r = 0; r < cDof; r++) { for (j = 0; j < aNumFillCols; j++) { PetscScalar inVal = 0; for (k = 0; k < aDof; k++) { PetscInt node = (o >= 0) ? (k / fComp) : ((aDof - 1 - k) / fComp); PetscInt comp = (k % fComp); PetscInt col = node * fComp + comp; inVal += pointMat[r * numCols + offset + col] * vals[aMatOffset + aNumFillCols * k + j]; } pointWork[r * aNumFillCols + j] = inVal; } } /* assume that the columns are sorted, spend less time searching */ for (j = 0, k = 0; j < aNumFillCols; j++) { PetscInt col = ja[aMatOffset + j]; for (;k < numFillCols; k++) { if (ja[matOffset + k] == col) { break; } } if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, col); for (r = 0; r < cDof; r++) { vals[matOffset + numFillCols * r + k] = pointWork[r * aNumFillCols + j]; } } } else { /* find where to put this portion of pointMat into the matrix */ for (k = 0; k < numFillCols; k++) { if (ja[matOffset + k] == aOff) { break; } } if (k == numFillCols) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No nonzero space for (%d, %d)", cOff, aOff); for (j = 0; j < aDof; j++) { PetscInt node = (o >= 0) ? (j / fComp) : ((aDof - 1 - j) / fComp); PetscInt comp = (j % fComp); PetscInt col = node * fComp + comp; for (r = 0; r < cDof; r++) { vals[matOffset + numFillCols * r + k + col] += pointMat[r * numCols + offset + col]; } } } offset += aDof; } } ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); } for (row = 0; row < nRows; row++) { ierr = MatSetValues(cMat,1,&row,ia[row+1]-ia[row],&ja[ia[row]],&vals[ia[row]],INSERT_VALUES);CHKERRQ(ierr); } ierr = MatRestoreRowIJ(cMat,0,PETSC_FALSE,PETSC_FALSE,&nRows,&ia,&ja,&done);CHKERRQ(ierr); if (!done) SETERRQ(PetscObjectComm((PetscObject)cMat),PETSC_ERR_PLIB,"Could not restore RowIJ of constraint matrix"); ierr = MatAssemblyBegin(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(cMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = PetscFree(vals);CHKERRQ(ierr); } /* clean up */ ierr = ISRestoreIndices(anIS,&anchors);CHKERRQ(ierr); ierr = PetscFree2(perm,iperm);CHKERRQ(ierr); ierr = PetscFree(pointWork);CHKERRQ(ierr); ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTreeRefineCell" /* refine a single cell on rank 0: this is not intended to provide good local refinement, only to create an example of * a non-conforming mesh. Local refinement comes later */ PetscErrorCode DMPlexTreeRefineCell (DM dm, PetscInt cell, DM *ncdm) { DM K; PetscMPIInt rank; PetscInt dim, *pNewStart, *pNewEnd, *pNewCount, *pOldStart, *pOldEnd, offset, d, pStart, pEnd; PetscInt numNewCones, *newConeSizes, *newCones, *newOrientations; PetscInt *Kembedding; PetscInt *cellClosure=NULL, nc; PetscScalar *newVertexCoords; PetscInt numPointsWithParents, *parents, *childIDs, *perm, *iperm, *preOrient, pOffset; PetscSection parentSection; PetscErrorCode ierr; PetscFunctionBegin; ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr); ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); ierr = DMPlexCreate(PetscObjectComm((PetscObject)dm), ncdm);CHKERRQ(ierr); ierr = DMSetDimension(*ncdm,dim);CHKERRQ(ierr); ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&parentSection);CHKERRQ(ierr); ierr = DMPlexGetReferenceTree(dm,&K);CHKERRQ(ierr); if (!rank) { /* compute the new charts */ ierr = PetscMalloc5(dim+1,&pNewCount,dim+1,&pNewStart,dim+1,&pNewEnd,dim+1,&pOldStart,dim+1,&pOldEnd);CHKERRQ(ierr); offset = 0; for (d = 0; d <= dim; d++) { PetscInt pOldCount, kStart, kEnd, k; pNewStart[d] = offset; ierr = DMPlexGetHeightStratum(dm,d,&pOldStart[d],&pOldEnd[d]);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr); pOldCount = pOldEnd[d] - pOldStart[d]; /* adding the new points */ pNewCount[d] = pOldCount + kEnd - kStart; if (!d) { /* removing the cell */ pNewCount[d]--; } for (k = kStart; k < kEnd; k++) { PetscInt parent; ierr = DMPlexGetTreeParent(K,k,&parent,NULL);CHKERRQ(ierr); if (parent == k) { /* avoid double counting points that won't actually be new */ pNewCount[d]--; } } pNewEnd[d] = pNewStart[d] + pNewCount[d]; offset = pNewEnd[d]; } if (cell < pOldStart[0] || cell >= pOldEnd[0]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"%d not in cell range [%d, %d)", cell, pOldStart[0], pOldEnd[0]); /* get the current closure of the cell that we are removing */ ierr = DMPlexGetTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr); ierr = PetscMalloc1(pNewEnd[dim],&newConeSizes);CHKERRQ(ierr); { PetscInt kStart, kEnd, k, closureSizeK, *closureK = NULL, j; ierr = DMPlexGetChart(K,&kStart,&kEnd);CHKERRQ(ierr); ierr = PetscMalloc4(kEnd-kStart,&Kembedding,kEnd-kStart,&perm,kEnd-kStart,&iperm,kEnd-kStart,&preOrient);CHKERRQ(ierr); for (k = kStart; k < kEnd; k++) { perm[k - kStart] = k; iperm [k - kStart] = k - kStart; preOrient[k - kStart] = 0; } ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr); for (j = 1; j < closureSizeK; j++) { PetscInt parentOrientA = closureK[2*j+1]; PetscInt parentOrientB = cellClosure[2*j+1]; PetscInt p, q; p = closureK[2*j]; q = cellClosure[2*j]; for (d = 0; d <= dim; d++) { if (q >= pOldStart[d] && q < pOldEnd[d]) { Kembedding[p] = (q - pOldStart[d]) + pNewStart[d]; } } if (parentOrientA != parentOrientB) { PetscInt numChildren, i; const PetscInt *children; ierr = DMPlexGetTreeChildren(K,p,&numChildren,&children);CHKERRQ(ierr); for (i = 0; i < numChildren; i++) { PetscInt kPerm, oPerm; k = children[i]; ierr = DMPlexReferenceTreeGetChildSymmetry(K,p,parentOrientA,0,k,parentOrientB,&oPerm,&kPerm);CHKERRQ(ierr); /* perm = what refTree position I'm in */ perm[kPerm-kStart] = k; /* iperm = who is at this position */ iperm[k-kStart] = kPerm-kStart; preOrient[kPerm-kStart] = oPerm; } } } ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&closureSizeK,&closureK);CHKERRQ(ierr); } ierr = PetscSectionSetChart(parentSection,0,pNewEnd[dim]);CHKERRQ(ierr); offset = 0; numNewCones = 0; for (d = 0; d <= dim; d++) { PetscInt kStart, kEnd, k; PetscInt p; PetscInt size; for (p = pOldStart[d]; p < pOldEnd[d]; p++) { /* skip cell 0 */ if (p == cell) continue; /* old cones to new cones */ ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr); newConeSizes[offset++] = size; numNewCones += size; } ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr); for (k = kStart; k < kEnd; k++) { PetscInt kParent; ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr); if (kParent != k) { Kembedding[k] = offset; ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr); newConeSizes[offset++] = size; numNewCones += size; if (kParent != 0) { ierr = PetscSectionSetDof(parentSection,Kembedding[k],1);CHKERRQ(ierr); } } } } ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(parentSection,&numPointsWithParents);CHKERRQ(ierr); ierr = PetscMalloc2(numNewCones,&newCones,numNewCones,&newOrientations);CHKERRQ(ierr); ierr = PetscMalloc2(numPointsWithParents,&parents,numPointsWithParents,&childIDs);CHKERRQ(ierr); /* fill new cones */ offset = 0; for (d = 0; d <= dim; d++) { PetscInt kStart, kEnd, k, l; PetscInt p; PetscInt size; const PetscInt *cone, *orientation; for (p = pOldStart[d]; p < pOldEnd[d]; p++) { /* skip cell 0 */ if (p == cell) continue; /* old cones to new cones */ ierr = DMPlexGetConeSize(dm,p,&size);CHKERRQ(ierr); ierr = DMPlexGetCone(dm,p,&cone);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm,p,&orientation);CHKERRQ(ierr); for (l = 0; l < size; l++) { newCones[offset] = (cone[l] - pOldStart[d + 1]) + pNewStart[d + 1]; newOrientations[offset++] = orientation[l]; } } ierr = DMPlexGetHeightStratum(K,d,&kStart,&kEnd);CHKERRQ(ierr); for (k = kStart; k < kEnd; k++) { PetscInt kPerm = perm[k], kParent; PetscInt preO = preOrient[k]; ierr = DMPlexGetTreeParent(K,k,&kParent,NULL);CHKERRQ(ierr); if (kParent != k) { /* embed new cones */ ierr = DMPlexGetConeSize(K,k,&size);CHKERRQ(ierr); ierr = DMPlexGetCone(K,kPerm,&cone);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(K,kPerm,&orientation);CHKERRQ(ierr); for (l = 0; l < size; l++) { PetscInt q, m = (preO >= 0) ? ((preO + l) % size) : ((size -(preO + 1) - l) % size); PetscInt newO, lSize, oTrue; q = iperm[cone[m]]; newCones[offset] = Kembedding[q]; ierr = DMPlexGetConeSize(K,q,&lSize);CHKERRQ(ierr); oTrue = orientation[m]; oTrue = ((!lSize) || (preOrient[k] >= 0)) ? oTrue : -(oTrue + 2); newO = DihedralCompose(lSize,oTrue,preOrient[q]); newOrientations[offset++] = newO; } if (kParent != 0) { PetscInt newPoint = Kembedding[kParent]; ierr = PetscSectionGetOffset(parentSection,Kembedding[k],&pOffset);CHKERRQ(ierr); parents[pOffset] = newPoint; childIDs[pOffset] = k; } } } } ierr = PetscMalloc1(dim*(pNewEnd[dim]-pNewStart[dim]),&newVertexCoords);CHKERRQ(ierr); /* fill coordinates */ offset = 0; { PetscInt kStart, kEnd, l; PetscSection vSection; PetscInt v; Vec coords; PetscScalar *coordvals; PetscInt dof, off; PetscReal v0[3], J[9], detJ; #if defined(PETSC_USE_DEBUG) { PetscInt k; ierr = DMPlexGetHeightStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr); for (k = kStart; k < kEnd; k++) { ierr = DMPlexComputeCellGeometryFEM(K, k, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr); if (detJ <= 0.) SETERRQ1 (PETSC_COMM_SELF,PETSC_ERR_PLIB,"reference tree cell %d has bad determinant",k); } } #endif ierr = DMPlexComputeCellGeometryFEM(dm, cell, NULL, v0, J, NULL, &detJ);CHKERRQ(ierr); ierr = DMGetCoordinateSection(dm,&vSection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm,&coords);CHKERRQ(ierr); ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr); for (v = pOldStart[dim]; v < pOldEnd[dim]; v++) { ierr = PetscSectionGetDof(vSection,v,&dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(vSection,v,&off);CHKERRQ(ierr); for (l = 0; l < dof; l++) { newVertexCoords[offset++] = coordvals[off + l]; } } ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr); ierr = DMGetCoordinateSection(K,&vSection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(K,&coords);CHKERRQ(ierr); ierr = VecGetArray(coords,&coordvals);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(K,0,&kStart,&kEnd);CHKERRQ(ierr); for (v = kStart; v < kEnd; v++) { PetscReal coord[3], newCoord[3]; PetscInt vPerm = perm[v]; PetscInt kParent; ierr = DMPlexGetTreeParent(K,v,&kParent,NULL);CHKERRQ(ierr); if (kParent != v) { /* this is a new vertex */ ierr = PetscSectionGetOffset(vSection,vPerm,&off);CHKERRQ(ierr); for (l = 0; l < dim; ++l) coord[l] = PetscRealPart(coordvals[off+l]); CoordinatesRefToReal(dim, dim, v0, J, coord, newCoord);CHKERRQ(ierr); for (l = 0; l < dim; ++l) newVertexCoords[offset+l] = newCoord[l]; offset += dim; } } ierr = VecRestoreArray(coords,&coordvals);CHKERRQ(ierr); } /* need to reverse the order of pNewCount: vertices first, cells last */ for (d = 0; d < (dim + 1) / 2; d++) { PetscInt tmp; tmp = pNewCount[d]; pNewCount[d] = pNewCount[dim - d]; pNewCount[dim - d] = tmp; } ierr = DMPlexCreateFromDAG(*ncdm,dim,pNewCount,newConeSizes,newCones,newOrientations,newVertexCoords);CHKERRQ(ierr); ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr); ierr = DMPlexSetTree(*ncdm,parentSection,parents,childIDs);CHKERRQ(ierr); /* clean up */ ierr = DMPlexRestoreTransitiveClosure(dm,cell,PETSC_TRUE,&nc,&cellClosure);CHKERRQ(ierr); ierr = PetscFree5(pNewCount,pNewStart,pNewEnd,pOldStart,pOldEnd);CHKERRQ(ierr); ierr = PetscFree(newConeSizes);CHKERRQ(ierr); ierr = PetscFree2(newCones,newOrientations);CHKERRQ(ierr); ierr = PetscFree(newVertexCoords);CHKERRQ(ierr); ierr = PetscFree2(parents,childIDs);CHKERRQ(ierr); ierr = PetscFree4(Kembedding,perm,iperm,preOrient);CHKERRQ(ierr); } else { PetscInt p, counts[4]; PetscInt *coneSizes, *cones, *orientations; Vec coordVec; PetscScalar *coords; for (d = 0; d <= dim; d++) { PetscInt dStart, dEnd; ierr = DMPlexGetDepthStratum(dm,d,&dStart,&dEnd);CHKERRQ(ierr); counts[d] = dEnd - dStart; } ierr = PetscMalloc1(pEnd-pStart,&coneSizes);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { ierr = DMPlexGetConeSize(dm,p,&coneSizes[p-pStart]);CHKERRQ(ierr); } ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); ierr = DMPlexGetConeOrientations(dm, &orientations);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm,&coordVec);CHKERRQ(ierr); ierr = VecGetArray(coordVec,&coords);CHKERRQ(ierr); ierr = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr); ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr); ierr = DMPlexCreateFromDAG(*ncdm,dim,counts,coneSizes,cones,orientations,NULL);CHKERRQ(ierr); ierr = DMPlexSetReferenceTree(*ncdm,K);CHKERRQ(ierr); ierr = DMPlexSetTree(*ncdm,parentSection,NULL,NULL);CHKERRQ(ierr); ierr = VecRestoreArray(coordVec,&coords);CHKERRQ(ierr); } ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexComputeInterpolatorTree" PetscErrorCode DMPlexComputeInterpolatorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) { PetscSF coarseToFineEmbedded; PetscSection globalCoarse, globalFine; PetscSection localCoarse, localFine; PetscSection aSec, cSec; PetscSection rootIndicesSec, rootMatricesSec; PetscSection leafIndicesSec, leafMatricesSec; PetscInt *rootIndices, *leafIndices; PetscScalar *rootMatrices, *leafMatrices; IS aIS; const PetscInt *anchors; Mat cMat; PetscInt numFields; PetscInt pStartC, pEndC, pStartF, pEndF, p; PetscInt aStart, aEnd, cStart, cEnd; PetscInt *maxChildIds; PetscInt *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr); { /* winnow fine points that don't have global dofs out of the sf */ PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs; for (p = pStartF, numPointsWithDofs = 0; p < pEndF; p++) { ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { numPointsWithDofs++; } } ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr); for (p = pStartF, offset = 0; p < pEndF; p++) { ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { pointsWithDofs[offset++] = p - pStartF; } } ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr); } /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */ ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { maxChildIds[p - pStartC] = -2; } ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr); ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,childIds,maxChildIds,MPIU_MAX);CHKERRQ(ierr); ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr); ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr); ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr); ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr); /* create sections that will send to children the indices and matrices they will need to construct the interpolator */ ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootMatricesSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(rootIndicesSec,pStartC,pEndC);CHKERRQ(ierr); ierr = PetscSectionSetChart(rootMatricesSec,pStartC,pEndC);CHKERRQ(ierr); ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr); { PetscInt maxFields = PetscMax(1,numFields) + 1; ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr); } for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */ PetscInt dof, matSize = 0; PetscInt aDof = 0; PetscInt cDof = 0; PetscInt maxChildId = maxChildIds[p - pStartC]; PetscInt numRowIndices = 0; PetscInt numColIndices = 0; PetscInt f; ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); if (dof < 0) { dof = -(dof + 1); } if (p >= aStart && p < aEnd) { ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr); } if (p >= cStart && p < cEnd) { ierr = PetscSectionGetDof(cSec,p,&cDof);CHKERRQ(ierr); } for (f = 0; f <= numFields; f++) offsets[f] = 0; for (f = 0; f <= numFields; f++) newOffsets[f] = 0; if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */ PetscInt *closure = NULL, closureSize, cl; ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize; cl++) { /* get the closure */ PetscInt c = closure[2 * cl], clDof; ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr); numRowIndices += clDof; for (f = 0; f < numFields; f++) { ierr = PetscSectionGetFieldDof(localCoarse,c,f,&clDof);CHKERRQ(ierr); offsets[f + 1] += clDof; } } for (f = 0; f < numFields; f++) { offsets[f + 1] += offsets[f]; newOffsets[f + 1] = offsets[f + 1]; } /* get the number of indices needed and their field offsets */ ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,NULL,NULL,&numColIndices,NULL,NULL,newOffsets,PETSC_FALSE);CHKERRQ(ierr); ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); if (!numColIndices) { /* there are no hanging constraint modifications, so the matrix is just the identity: do not send it */ numColIndices = numRowIndices; matSize = 0; } else if (numFields) { /* we send one submat for each field: sum their sizes */ matSize = 0; for (f = 0; f < numFields; f++) { PetscInt numRow, numCol; numRow = offsets[f + 1] - offsets[f]; numCol = newOffsets[f + 1] - newOffsets[f]; matSize += numRow * numCol; } } else { matSize = numRowIndices * numColIndices; } } else if (maxChildId == -1) { if (cDof > 0) { /* this point's dofs are interpolated via cMat: get the submatrix of cMat */ PetscInt aOff, a; ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr); offsets[f+1] = fDof; } for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff], aLocalDof; ierr = PetscSectionGetDof(localCoarse,anchor,&aLocalDof);CHKERRQ(ierr); numColIndices += aLocalDof; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr); newOffsets[f+1] += fDof; } } if (numFields) { matSize = 0; for (f = 0; f < numFields; f++) { matSize += offsets[f+1] * newOffsets[f+1]; } } else { matSize = numColIndices * dof; } } else { /* no children, and no constraints on dofs: just get the global indices */ numColIndices = dof; matSize = 0; } } /* we will pack the column indices with the field offsets */ ierr = PetscSectionSetDof(rootIndicesSec,p,numColIndices ? numColIndices+2*numFields : 0);CHKERRQ(ierr); ierr = PetscSectionSetDof(rootMatricesSec,p,matSize);CHKERRQ(ierr); } ierr = PetscSectionSetUp(rootIndicesSec);CHKERRQ(ierr); ierr = PetscSectionSetUp(rootMatricesSec);CHKERRQ(ierr); { PetscInt numRootIndices, numRootMatrices; ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(rootMatricesSec,&numRootMatrices);CHKERRQ(ierr); ierr = PetscMalloc2(numRootIndices,&rootIndices,numRootMatrices,&rootMatrices);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt numRowIndices, numColIndices, matSize, dof; PetscInt pIndOff, pMatOff, f; PetscInt *pInd; PetscInt maxChildId = maxChildIds[p - pStartC]; PetscScalar *pMat = NULL; ierr = PetscSectionGetDof(rootIndicesSec,p,&numColIndices);CHKERRQ(ierr); if (!numColIndices) { continue; } for (f = 0; f <= numFields; f++) { offsets[f] = 0; newOffsets[f] = 0; offsetsCopy[f] = 0; newOffsetsCopy[f] = 0; } numColIndices -= 2 * numFields; ierr = PetscSectionGetOffset(rootIndicesSec,p,&pIndOff);CHKERRQ(ierr); pInd = &(rootIndices[pIndOff]); ierr = PetscSectionGetDof(rootMatricesSec,p,&matSize);CHKERRQ(ierr); if (matSize) { ierr = PetscSectionGetOffset(rootMatricesSec,p,&pMatOff);CHKERRQ(ierr); pMat = &rootMatrices[pMatOff]; } ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); if (dof < 0) { dof = -(dof + 1); } if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */ PetscInt i, j; PetscInt numRowIndices = matSize / numColIndices; if (!numRowIndices) { /* don't need to calculate the mat, just the indices */ PetscInt numIndices, *indices; ierr = DMPlexGetClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr); if (numIndices != numColIndices) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"mismatching constraint indices calculations"); for (i = 0; i < numColIndices; i++) { pInd[i] = indices[i]; } for (i = 0; i < numFields; i++) { pInd[numColIndices + i] = offsets[i+1]; pInd[numColIndices + numFields + i] = offsets[i+1]; } ierr = DMPlexRestoreClosureIndices(coarse,localCoarse,globalCoarse,p,&numIndices,&indices,offsets);CHKERRQ(ierr); } else { PetscInt closureSize, *closure = NULL, cl; PetscScalar *pMatIn, *pMatModified; PetscInt numPoints,*points; ierr = DMGetWorkArray(coarse,numRowIndices * numRowIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr); for (i = 0; i < numRowIndices; i++) { /* initialize to the identity */ for (j = 0; j < numRowIndices; j++) { pMatIn[i * numRowIndices + j] = (i == j) ? 1. : 0.; } } ierr = DMPlexGetTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); if (numFields) { for (cl = 0; cl < closureSize; cl++) { PetscInt c = closure[2 * cl]; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,c,f,&fDof);CHKERRQ(ierr); offsets[f + 1] += fDof; } } for (f = 0; f < numFields; f++) { offsets[f + 1] += offsets[f]; newOffsets[f + 1] = offsets[f + 1]; } } /* apply hanging node constraints on the right, get the new points and the new offsets */ ierr = DMPlexAnchorsModifyMat(coarse,localCoarse,closureSize,numRowIndices,closure,pMatIn,&numPoints,NULL,&points,&pMatModified,newOffsets,PETSC_FALSE);CHKERRQ(ierr); if (!numFields) { for (i = 0; i < numRowIndices * numColIndices; i++) { pMat[i] = pMatModified[i]; } } else { PetscInt i, j, count; for (f = 0, count = 0; f < numFields; f++) { for (i = offsets[f]; i < offsets[f+1]; i++) { for (j = newOffsets[f]; j < newOffsets[f+1]; j++, count++) { pMat[count] = pMatModified[i * numColIndices + j]; } } } } ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatModified);CHKERRQ(ierr); ierr = DMPlexRestoreTransitiveClosure(coarse, p, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); ierr = DMRestoreWorkArray(coarse,numRowIndices * numColIndices,PETSC_SCALAR,&pMatIn);CHKERRQ(ierr); if (numFields) { for (f = 0; f < numFields; f++) { pInd[numColIndices + f] = offsets[f+1]; pInd[numColIndices + numFields + f] = newOffsets[f+1]; } for (cl = 0; cl < numPoints*2; cl += 2) { PetscInt o = points[cl+1], globalOff, c = points[cl]; ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr); DMPlexGetIndicesPointFields_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd); } } else { for (cl = 0; cl < numPoints*2; cl += 2) { PetscInt o = points[cl+1], c = points[cl], globalOff; ierr = PetscSectionGetOffset(globalCoarse, c, &globalOff);CHKERRQ(ierr); DMPlexGetIndicesPoint_Internal(localCoarse, c, globalOff < 0 ? -(globalOff+1) : globalOff, newOffsets, PETSC_FALSE, o, pInd); } } ierr = DMRestoreWorkArray(coarse,numPoints,PETSC_SCALAR,&points);CHKERRQ(ierr); } } else if (matSize) { PetscInt cOff; PetscInt *rowIndices, *colIndices, a, aDof, aOff; numRowIndices = matSize / numColIndices; if (numRowIndices != dof) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Miscounted dofs"); ierr = DMGetWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr); ierr = DMGetWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(cSec,p,&cOff);CHKERRQ(ierr); ierr = PetscSectionGetDof(aSec,p,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(aSec,p,&aOff);CHKERRQ(ierr); if (numFields) { for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(cSec,p,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof; for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff]; ierr = PetscSectionGetFieldDof(localCoarse,anchor,f,&fDof);CHKERRQ(ierr); newOffsets[f + 1] += fDof; } } for (f = 0; f < numFields; f++) { offsets[f + 1] += offsets[f]; offsetsCopy[f + 1] = offsets[f + 1]; newOffsets[f + 1] += newOffsets[f]; newOffsetsCopy[f + 1] = newOffsets[f + 1]; } DMPlexGetIndicesPointFields_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr); for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff], lOff; ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr); DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr); } } else { DMPlexGetIndicesPoint_Internal(cSec,p,cOff,offsetsCopy,PETSC_TRUE,0,rowIndices);CHKERRQ(ierr); for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff], lOff; ierr = PetscSectionGetOffset(localCoarse,anchor,&lOff);CHKERRQ(ierr); DMPlexGetIndicesPoint_Internal(localCoarse,anchor,lOff,newOffsetsCopy,PETSC_TRUE,0,colIndices);CHKERRQ(ierr); } } if (numFields) { PetscInt count, a; for (f = 0, count = 0; f < numFields; f++) { PetscInt iSize = offsets[f + 1] - offsets[f]; PetscInt jSize = newOffsets[f + 1] - newOffsets[f]; ierr = MatGetValues(cMat,iSize,&rowIndices[offsets[f]],jSize,&colIndices[newOffsets[f]],&pMat[count]);CHKERRQ(ierr); count += iSize * jSize; pInd[numColIndices + f] = offsets[f+1]; pInd[numColIndices + numFields + f] = newOffsets[f+1]; } for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff]; PetscInt gOff; ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr); DMPlexGetIndicesPointFields_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } } else { PetscInt a; ierr = MatGetValues(cMat,numRowIndices,rowIndices,numColIndices,colIndices,pMat);CHKERRQ(ierr); for (a = 0; a < aDof; a++) { PetscInt anchor = anchors[a + aOff]; PetscInt gOff; ierr = PetscSectionGetOffset(globalCoarse,anchor,&gOff);CHKERRQ(ierr); DMPlexGetIndicesPoint_Internal(localCoarse,anchor,gOff < 0 ? -(gOff + 1) : gOff,newOffsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } } ierr = DMRestoreWorkArray(coarse,numColIndices,PETSC_INT,&colIndices);CHKERRQ(ierr); ierr = DMRestoreWorkArray(coarse,numRowIndices,PETSC_INT,&rowIndices);CHKERRQ(ierr); } else { PetscInt gOff; ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr); if (numFields) { for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof + offsets[f]; } for (f = 0; f < numFields; f++) { pInd[numColIndices + f] = offsets[f+1]; pInd[numColIndices + numFields + f] = offsets[f+1]; } DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } else { DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } } } ierr = PetscFree(maxChildIds);CHKERRQ(ierr); } { PetscSF indicesSF, matricesSF; PetscInt *remoteOffsetsIndices, *remoteOffsetsMatrices, numLeafIndices, numLeafMatrices; ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafMatricesSec);CHKERRQ(ierr); ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootIndicesSec,&remoteOffsetsIndices,leafIndicesSec);CHKERRQ(ierr); ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootMatricesSec,&remoteOffsetsMatrices,leafMatricesSec);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootIndicesSec,remoteOffsetsIndices,leafIndicesSec,&indicesSF);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootMatricesSec,remoteOffsetsMatrices,leafMatricesSec,&matricesSF);CHKERRQ(ierr); ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(remoteOffsetsIndices);CHKERRQ(ierr); ierr = PetscFree(remoteOffsetsMatrices);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafIndicesSec,&numLeafIndices);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafMatricesSec,&numLeafMatrices);CHKERRQ(ierr); ierr = PetscMalloc2(numLeafIndices,&leafIndices,numLeafMatrices,&leafMatrices);CHKERRQ(ierr); ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr); ierr = PetscSFBcastBegin(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr); ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,rootIndices,leafIndices);CHKERRQ(ierr); ierr = PetscSFBcastEnd(matricesSF,MPIU_SCALAR,rootMatrices,leafMatrices);CHKERRQ(ierr); ierr = PetscSFDestroy(&matricesSF);CHKERRQ(ierr); ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr); ierr = PetscFree2(rootIndices,rootMatrices);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootMatricesSec);CHKERRQ(ierr); } /* count to preallocate */ ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr); { PetscInt nGlobal; PetscInt *dnnz, *onnz; PetscLayout rowMap, colMap; PetscInt rowStart, rowEnd, colStart, colEnd; PetscInt maxDof; PetscInt *rowIndices; DM refTree; PetscInt **refPointFieldN; PetscScalar ***refPointFieldMats; PetscSection refConSec, refAnSec; PetscInt pRefStart,pRefEnd,maxConDof,maxColumns,leafStart,leafEnd; PetscScalar *pointWork; ierr = PetscSectionGetConstrainedStorageSize(globalFine,&nGlobal);CHKERRQ(ierr); ierr = PetscCalloc2(nGlobal,&dnnz,nGlobal,&onnz);CHKERRQ(ierr); ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr); ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr); ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr); ierr = PetscSectionGetChart(leafIndicesSec,&leafStart,&leafEnd);CHKERRQ(ierr); ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr); for (p = leafStart; p < leafEnd; p++) { PetscInt gDof, gcDof, gOff; PetscInt numColIndices, pIndOff, *pInd; PetscInt matSize; PetscInt i; ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr); if ((gDof - gcDof) <= 0) { continue; } ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr); if (gOff < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I though having global dofs meant a non-negative offset"); if ((gOff < rowStart) || ((gOff + gDof - gcDof) > rowEnd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"I thought the row map would constrain the global dofs"); ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr); numColIndices -= 2 * numFields; if (numColIndices <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"global fine dof with no dofs to interpolate from"); pInd = &leafIndices[pIndOff]; offsets[0] = 0; offsetsCopy[0] = 0; newOffsets[0] = 0; newOffsetsCopy[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt rowDof; ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr); offsets[f + 1] = offsets[f] + rowDof; offsetsCopy[f + 1] = offsets[f + 1]; newOffsets[f + 1] = pInd[numColIndices + numFields + f]; numD[f] = 0; numO[f] = 0; } ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscInt colOffset = newOffsets[f]; PetscInt numFieldCols = newOffsets[f + 1] - newOffsets[f]; for (i = 0; i < numFieldCols; i++) { PetscInt gInd = pInd[i + colOffset]; if (gInd >= colStart && gInd < colEnd) { numD[f]++; } else if (gInd >= 0) { /* negative means non-entry */ numO[f]++; } } } } else { ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); numD[0] = 0; numO[0] = 0; for (i = 0; i < numColIndices; i++) { PetscInt gInd = pInd[i]; if (gInd >= colStart && gInd < colEnd) { numD[0]++; } else if (gInd >= 0) { /* negative means non-entry */ numO[0]++; } } } ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr); if (!matSize) { /* incoming matrix is identity */ PetscInt childId; childId = childIds[p-pStartF]; if (childId < 0) { /* no child interpolation: one nnz per */ if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1] - offsets[f], row; for (row = 0; row < numRows; row++) { PetscInt gIndCoarse = pInd[newOffsets[f] + row]; PetscInt gIndFine = rowIndices[offsets[f] + row]; if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */ if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = 1; } else if (gIndCoarse >= 0) { /* remote */ if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); onnz[gIndFine - rowStart] = 1; } else { /* constrained */ if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); } } } } else { PetscInt i; for (i = 0; i < gDof; i++) { PetscInt gIndCoarse = pInd[i]; PetscInt gIndFine = rowIndices[i]; if (gIndCoarse >= colStart && gIndCoarse < colEnd) { /* local */ if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = 1; } else if (gIndCoarse >= 0) { /* remote */ if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); onnz[gIndFine - rowStart] = 1; } else { /* constrained */ if (gIndFine >= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); } } } } else { /* interpolate from all */ if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1] - offsets[f], row; for (row = 0; row < numRows; row++) { PetscInt gIndFine = rowIndices[offsets[f] + row]; if (gIndFine >= 0) { if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = numD[f]; onnz[gIndFine - rowStart] = numO[f]; } } } } else { PetscInt i; for (i = 0; i < gDof; i++) { PetscInt gIndFine = rowIndices[i]; if (gIndFine >= 0) { if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = numD[0]; onnz[gIndFine - rowStart] = numO[0]; } } } } } else { /* interpolate from all */ if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1] - offsets[f], row; for (row = 0; row < numRows; row++) { PetscInt gIndFine = rowIndices[offsets[f] + row]; if (gIndFine >= 0) { if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = numD[f]; onnz[gIndFine - rowStart] = numO[f]; } } } } else { /* every dof get a full row */ PetscInt i; for (i = 0; i < gDof; i++) { PetscInt gIndFine = rowIndices[i]; if (gIndFine >= 0) { if (gIndFine < rowStart || gIndFine >= rowEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mismatched number of constrained dofs"); dnnz[gIndFine - rowStart] = numD[0]; onnz[gIndFine - rowStart] = numO[0]; } } } } } ierr = MatXAIJSetPreallocation(mat,1,dnnz,onnz,NULL,NULL);CHKERRQ(ierr); ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr); ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr); ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr); ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refConSec,&maxConDof);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(leafIndicesSec,&maxColumns);CHKERRQ(ierr); ierr = PetscMalloc1(maxConDof*maxColumns,&pointWork);CHKERRQ(ierr); for (p = leafStart; p < leafEnd; p++) { PetscInt gDof, gcDof, gOff; PetscInt numColIndices, pIndOff, *pInd; PetscInt matSize; PetscInt childId; ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr); if ((gDof - gcDof) <= 0) { continue; } childId = childIds[p-pStartF]; ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr); ierr = PetscSectionGetDof(leafIndicesSec,p,&numColIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(leafIndicesSec,p,&pIndOff);CHKERRQ(ierr); numColIndices -= 2 * numFields; pInd = &leafIndices[pIndOff]; offsets[0] = 0; offsetsCopy[0] = 0; newOffsets[0] = 0; newOffsetsCopy[0] = 0; rowOffsets[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt rowDof; ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr); offsets[f + 1] = offsets[f] + rowDof; offsetsCopy[f + 1] = offsets[f + 1]; rowOffsets[f + 1] = pInd[numColIndices + f]; newOffsets[f + 1] = pInd[numColIndices + numFields + f]; } ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); } else { ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); } ierr = PetscSectionGetDof(leafMatricesSec,p,&matSize);CHKERRQ(ierr); if (!matSize) { /* incoming matrix is identity */ if (childId < 0) { /* no child interpolation: scatter */ if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1] - offsets[f], row; for (row = 0; row < numRows; row++) { ierr = MatSetValue(mat,rowIndices[offsets[f]+row],pInd[newOffsets[f]+row],1.,INSERT_VALUES);CHKERRQ(ierr); } } } else { PetscInt numRows = gDof, row; for (row = 0; row < numRows; row++) { ierr = MatSetValue(mat,rowIndices[row],pInd[row],1.,INSERT_VALUES);CHKERRQ(ierr); } } } else { /* interpolate from all */ if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1] - offsets[f]; PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],refPointFieldMats[childId - pRefStart][f],INSERT_VALUES);CHKERRQ(ierr); } } else { ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,refPointFieldMats[childId - pRefStart][0],INSERT_VALUES);CHKERRQ(ierr); } } } else { /* interpolate from all */ PetscInt pMatOff; PetscScalar *pMat; ierr = PetscSectionGetOffset(leafMatricesSec,p,&pMatOff);CHKERRQ(ierr); pMat = &leafMatrices[pMatOff]; if (childId < 0) { /* copy the incoming matrix */ if (numFields) { PetscInt f, count; for (f = 0, count = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1]-offsets[f]; PetscInt numCols = newOffsets[f+1]-newOffsets[f]; PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f]; PetscScalar *inMat = &pMat[count]; ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],inMat,INSERT_VALUES);CHKERRQ(ierr); count += numCols * numInRows; } } else { ierr = MatSetValues(mat,gDof,rowIndices,numColIndices,pInd,pMat,INSERT_VALUES);CHKERRQ(ierr); } } else { /* multiply the incoming matrix by the child interpolation */ if (numFields) { PetscInt f, count; for (f = 0, count = 0; f < numFields; f++) { PetscInt numRows = offsets[f+1]-offsets[f]; PetscInt numCols = newOffsets[f+1]-newOffsets[f]; PetscInt numInRows = rowOffsets[f+1]-rowOffsets[f]; PetscScalar *inMat = &pMat[count]; PetscInt i, j, k; if (refPointFieldN[childId - pRefStart][f] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch"); for (i = 0; i < numRows; i++) { for (j = 0; j < numCols; j++) { PetscScalar val = 0.; for (k = 0; k < numInRows; k++) { val += refPointFieldMats[childId - pRefStart][f][i * numInRows + k] * inMat[k * numCols + j]; } pointWork[i * numCols + j] = val; } } ierr = MatSetValues(mat,numRows,&rowIndices[offsets[f]],numCols,&pInd[newOffsets[f]],pointWork,INSERT_VALUES);CHKERRQ(ierr); count += numCols * numInRows; } } else { /* every dof gets a full row */ PetscInt numRows = gDof; PetscInt numCols = numColIndices; PetscInt numInRows = matSize / numColIndices; PetscInt i, j, k; if (refPointFieldN[childId - pRefStart][0] != numInRows) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Point constraint matrix multiply dimension mismatch"); for (i = 0; i < numRows; i++) { for (j = 0; j < numCols; j++) { PetscScalar val = 0.; for (k = 0; k < numInRows; k++) { val += refPointFieldMats[childId - pRefStart][0][i * numInRows + k] * pMat[k * numCols + j]; } pointWork[i * numCols + j] = val; } } ierr = MatSetValues(mat,numRows,rowIndices,numCols,pInd,pointWork,INSERT_VALUES);CHKERRQ(ierr); } } } } ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr); ierr = PetscFree(pointWork);CHKERRQ(ierr); } ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr); ierr = PetscSectionDestroy(&leafMatricesSec);CHKERRQ(ierr); ierr = PetscFree2(leafIndices,leafMatrices);CHKERRQ(ierr); ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr); ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexComputeInjectorReferenceTree" /* * Assuming a nodal basis (w.r.t. the dual basis) basis: * * for each coarse dof \phi^c_i: * for each quadrature point (w_l,x_l) in the dual basis definition of \phi^c_i: * for each fine dof \phi^f_j; * a_{i,j} = 0; * for each fine dof \phi^f_k: * a_{i,j} += interp_{i,k} * \phi^f_k(x_l) * \phi^f_j(x_l) * w_l * [^^^ this is = \phi^c_i ^^^] */ PetscErrorCode DMPlexComputeInjectorReferenceTree(DM refTree, Mat *inj) { PetscDS ds; PetscSection section, cSection; DMLabel canonical, depth; Mat cMat, mat; PetscInt *nnz; PetscInt f, dim, numFields, numSecFields, p, pStart, pEnd, cStart, cEnd; PetscInt m, n; PetscScalar *pointScalar; PetscReal *v0, *v0parent, *vtmp, *J, *Jparent, *invJ, *pointRef, detJ, detJparent; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDefaultSection(refTree,§ion);CHKERRQ(ierr); ierr = DMGetDimension(refTree, &dim);CHKERRQ(ierr); ierr = PetscMalloc6(dim,&v0,dim,&v0parent,dim,&vtmp,dim*dim,&J,dim*dim,&Jparent,dim*dim,&invJ);CHKERRQ(ierr); ierr = PetscMalloc2(dim,&pointScalar,dim,&pointRef);CHKERRQ(ierr); ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = PetscSectionGetNumFields(section,&numSecFields);CHKERRQ(ierr); ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr); ierr = DMGetLabel(refTree,"depth",&depth);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&cSection,&cMat);CHKERRQ(ierr); ierr = DMPlexGetChart(refTree, &pStart, &pEnd);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(refTree, 0, &cStart, &cEnd);CHKERRQ(ierr); ierr = MatGetSize(cMat,&n,&m);CHKERRQ(ierr); /* the injector has transpose sizes from the constraint matrix */ /* Step 1: compute non-zero pattern. A proper subset of constraint matrix non-zero */ ierr = PetscCalloc1(m,&nnz);CHKERRQ(ierr); for (p = pStart; p < pEnd; p++) { /* a point will have non-zeros if it is canonical, it has dofs, and its children have dofs */ const PetscInt *children; PetscInt numChildren; PetscInt i, numChildDof, numSelfDof; if (canonical) { PetscInt pCanonical; ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr); if (p != pCanonical) continue; } ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr); if (!numChildren) continue; for (i = 0, numChildDof = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscInt dof; ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr); numChildDof += dof; } ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr); if (!numChildDof || !numSelfDof) continue; for (f = 0; f < numFields; f++) { PetscInt selfOff; if (numSecFields) { /* count the dofs for just this field */ for (i = 0, numChildDof = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscInt dof; ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr); numChildDof += dof; } ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr); } for (i = 0; i < numSelfDof; i++) { nnz[selfOff + i] = numChildDof; } } } ierr = MatCreateAIJ(PETSC_COMM_SELF,m,n,m,n,-1,nnz,-1,NULL,&mat);CHKERRQ(ierr); ierr = PetscFree(nnz);CHKERRQ(ierr); /* Setp 2: compute entries */ for (p = pStart; p < pEnd; p++) { const PetscInt *children; PetscInt numChildren; PetscInt i, numChildDof, numSelfDof; /* same conditions about when entries occur */ if (canonical) { PetscInt pCanonical; ierr = DMLabelGetValue(canonical,p,&pCanonical);CHKERRQ(ierr); if (p != pCanonical) continue; } ierr = DMPlexGetTreeChildren(refTree,p,&numChildren,&children);CHKERRQ(ierr); if (!numChildren) continue; for (i = 0, numChildDof = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscInt dof; ierr = PetscSectionGetDof(section,child,&dof);CHKERRQ(ierr); numChildDof += dof; } ierr = PetscSectionGetDof(section,p,&numSelfDof);CHKERRQ(ierr); if (!numChildDof || !numSelfDof) continue; for (f = 0; f < numFields; f++) { PetscInt selfOff, fComp, numSelfShapes, numChildShapes, parentCell; PetscInt cellShapeOff; PetscObject disc; PetscDualSpace dsp; PetscClassId classId; PetscScalar *pointMat; PetscInt *matRows, *matCols; PetscInt pO = PETSC_MIN_INT; const PetscInt *depthNumDof; if (numSecFields) { for (i = 0, numChildDof = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscInt dof; ierr = PetscSectionGetFieldDof(section,child,f,&dof);CHKERRQ(ierr); numChildDof += dof; } ierr = PetscSectionGetFieldDof(section,p,f,&numSelfDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(section,p,f,&selfOff);CHKERRQ(ierr); ierr = PetscSectionGetFieldComponents(section,f,&fComp);CHKERRQ(ierr); } else { ierr = PetscSectionGetOffset(section,p,&selfOff);CHKERRQ(ierr); fComp = 1; } numSelfShapes = numSelfDof / fComp; numChildShapes = numChildDof / fComp; /* find a cell whose closure contains p */ if (p >= cStart && p < cEnd) { parentCell = p; } else { PetscInt *star = NULL; PetscInt numStar; parentCell = -1; ierr = DMPlexGetTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr); for (i = numStar - 1; i >= 0; i--) { PetscInt c = star[2 * i]; if (c >= cStart && c < cEnd) { parentCell = c; break; } } ierr = DMPlexRestoreTransitiveClosure(refTree,p,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr); } /* determine the offset of p's shape functions withing parentCell's shape functions */ ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr); ierr = PetscObjectGetClassId(disc,&classId);CHKERRQ(ierr); if (classId == PETSCFE_CLASSID) { ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr); } else if (classId == PETSCFV_CLASSID) { ierr = PetscFVGetDualSpace((PetscFV)disc,&dsp);CHKERRQ(ierr); } else { SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported discretization object");CHKERRQ(ierr); } ierr = PetscDualSpaceGetNumDof(dsp,&depthNumDof);CHKERRQ(ierr); { PetscInt *closure = NULL; PetscInt numClosure; ierr = DMPlexGetTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr); for (i = 0, cellShapeOff = 0; i < numClosure; i++) { PetscInt point = closure[2 * i], pointDepth; pO = closure[2 * i + 1]; if (point == p) break; ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr); cellShapeOff += depthNumDof[pointDepth]; } ierr = DMPlexRestoreTransitiveClosure(refTree,parentCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr); } ierr = DMGetWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr); ierr = DMGetWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr); matCols = matRows + numSelfShapes; for (i = 0; i < numSelfShapes; i++) { matRows[i] = selfOff + i * fComp; } { PetscInt colOff = 0; for (i = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscInt dof, off, j; if (numSecFields) { ierr = PetscSectionGetFieldDof(cSection,child,f,&dof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(cSection,child,f,&off);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(cSection,child,&dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(cSection,child,&off);CHKERRQ(ierr); } for (j = 0; j < dof / fComp; j++) { matCols[colOff++] = off + j * fComp; } } } if (classId == PETSCFE_CLASSID) { PetscFE fe = (PetscFE) disc; PetscInt fSize; ierr = PetscFEGetDualSpace(fe,&dsp);CHKERRQ(ierr); ierr = PetscDualSpaceGetDimension(dsp,&fSize);CHKERRQ(ierr); for (i = 0; i < numSelfShapes; i++) { /* for every shape function */ PetscQuadrature q; PetscInt dim, numPoints, j, k; const PetscReal *points; const PetscReal *weights; PetscInt *closure = NULL; PetscInt numClosure; PetscInt parentCellShapeDof = cellShapeOff + (pO < 0 ? (numSelfShapes - 1 - i) : i); PetscReal *Bparent; ierr = PetscDualSpaceGetFunctional(dsp,parentCellShapeDof,&q);CHKERRQ(ierr); ierr = PetscQuadratureGetData(q,&dim,&numPoints,&points,&weights);CHKERRQ(ierr); ierr = PetscFEGetTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); /* I'm expecting a nodal basis: weights[:]' * Bparent[:,cellShapeDof] = 1. */ for (k = 0; k < numChildShapes; k++) { pointMat[numChildShapes * i + k] = 0.; } for (j = 0; j < numPoints; j++) { PetscInt childCell = -1; PetscReal parentValAtPoint; const PetscReal *pointReal = &points[dim * j]; const PetscScalar *point; PetscReal *Bchild; PetscInt childCellShapeOff, pointMatOff; #if defined(PETSC_USE_COMPLEX) PetscInt d; for (d = 0; d < dim; d++) { pointScalar[d] = points[dim * j + d]; } point = pointScalar; #else point = pointReal; #endif parentValAtPoint = Bparent[(fSize * j + parentCellShapeDof) * fComp]; for (k = 0; k < numChildren; k++) { /* locate the point in a child's star cell*/ PetscInt child = children[k]; PetscInt *star = NULL; PetscInt numStar, s; ierr = DMPlexGetTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr); for (s = numStar - 1; s >= 0; s--) { PetscInt c = star[2 * s]; if (c < cStart || c >= cEnd) continue; ierr = DMPlexLocatePoint_Internal(refTree,dim,point,c,&childCell);CHKERRQ(ierr); if (childCell >= 0) break; } ierr = DMPlexRestoreTransitiveClosure(refTree,child,PETSC_FALSE,&numStar,&star);CHKERRQ(ierr); if (childCell >= 0) break; } if (childCell < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not locate quadrature point");CHKERRQ(ierr); ierr = DMPlexComputeCellGeometryFEM(refTree, childCell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); ierr = DMPlexComputeCellGeometryFEM(refTree, parentCell, NULL, v0parent, Jparent, NULL, &detJparent);CHKERRQ(ierr); CoordinatesRefToReal(dim, dim, v0parent, Jparent, pointReal, vtmp); CoordinatesRealToRef(dim, dim, v0, invJ, vtmp, pointRef); ierr = PetscFEGetTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr); ierr = DMPlexGetTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr); for (k = 0, pointMatOff = 0; k < numChildren; k++) { /* point is located in cell => child dofs support at point are in closure of cell */ PetscInt child = children[k], childDepth, childDof, childO = PETSC_MIN_INT; PetscInt l; ierr = DMLabelGetValue(depth,child,&childDepth);CHKERRQ(ierr); childDof = depthNumDof[childDepth]; for (l = 0, childCellShapeOff = 0; l < numClosure; l++) { PetscInt point = closure[2 * l]; PetscInt pointDepth; childO = closure[2 * l + 1]; if (point == child) break; ierr = DMLabelGetValue(depth,point,&pointDepth);CHKERRQ(ierr); childCellShapeOff += depthNumDof[pointDepth]; } if (l == numClosure) { pointMatOff += childDof; continue; /* child is not in the closure of the cell: has nothing to contribute to this point */ } for (l = 0; l < childDof; l++) { PetscInt childCellDof = childCellShapeOff + (childO ? (childDof - 1 - l) : l); PetscReal childValAtPoint = Bchild[childCellDof * fComp]; pointMat[i * numChildShapes + pointMatOff + l] += weights[j] * parentValAtPoint * childValAtPoint; } pointMatOff += childDof; } ierr = DMPlexRestoreTransitiveClosure(refTree,childCell,PETSC_TRUE,&numClosure,&closure);CHKERRQ(ierr); ierr = PetscFERestoreTabulation(fe,1,pointRef,&Bchild,NULL,NULL);CHKERRQ(ierr); } ierr = PetscFERestoreTabulation(fe,numPoints,points,&Bparent,NULL,NULL);CHKERRQ(ierr); } } else { /* just the volume-weighted averages of the children */ PetscInt childShapeOff; PetscReal parentVol; ierr = DMPlexComputeCellGeometryFVM(refTree, p, &parentVol, NULL, NULL);CHKERRQ(ierr); for (i = 0, childShapeOff = 0; i < numChildren; i++) { PetscInt child = children[i]; PetscReal childVol; if (child < cStart || child >= cEnd) continue; ierr = DMPlexComputeCellGeometryFVM(refTree, child, &childVol, NULL, NULL);CHKERRQ(ierr); pointMat[childShapeOff] = childVol / parentVol; childShapeOff++; } } /* Insert pointMat into mat */ for (i = 0; i < fComp; i++) { PetscInt j; ierr = MatSetValues(mat,numSelfShapes,matRows,numChildShapes,matCols,pointMat,INSERT_VALUES);CHKERRQ(ierr); for (j = 0; j < numSelfShapes; j++) { matRows[j]++; } for (j = 0; j < numChildShapes; j++) { matCols[j]++; } } ierr = DMRestoreWorkArray(refTree, numSelfShapes + numChildShapes, PETSC_INT,&matRows);CHKERRQ(ierr); ierr = DMRestoreWorkArray(refTree, numSelfShapes * numChildShapes, PETSC_SCALAR,&pointMat);CHKERRQ(ierr); } } ierr = PetscFree6(v0,v0parent,vtmp,J,Jparent,invJ);CHKERRQ(ierr); ierr = PetscFree2(pointScalar,pointRef);CHKERRQ(ierr); ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); *inj = mat; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeGetChildrenMatrices_Injection" static PetscErrorCode DMPlexReferenceTreeGetChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) { PetscDS ds; PetscInt numFields, f, pRefStart, pRefEnd, p, *rows, *cols, maxDof; PetscScalar ***refPointFieldMats; PetscSection refConSec, refSection; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr); ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = PetscMalloc1(pRefEnd-pRefStart,&refPointFieldMats);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(refConSec,&maxDof);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof,&rows);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof*maxDof,&cols);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt parent, pDof, parentDof; ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr); ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr); ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr); if (!pDof || !parentDof || parent == p) continue; ierr = PetscMalloc1(numFields,&refPointFieldMats[p-pRefStart]);CHKERRQ(ierr); for (f = 0; f < numFields; f++) { PetscInt cDof, cOff, numCols, r, fComp; PetscObject disc; PetscClassId id; PetscFE fe = NULL; PetscFV fv = NULL; ierr = PetscDSGetDiscretization(ds,f,&disc);CHKERRQ(ierr); ierr = PetscObjectGetClassId(disc,&id);CHKERRQ(ierr); if (id == PETSCFE_CLASSID) { fe = (PetscFE) disc; ierr = PetscFEGetNumComponents(fe,&fComp);CHKERRQ(ierr); } else if (id == PETSCFV_CLASSID) { fv = (PetscFV) disc; ierr = PetscFVGetNumComponents(fv,&fComp);CHKERRQ(ierr); } else SETERRQ1(PetscObjectComm(disc),PETSC_ERR_ARG_UNKNOWN_TYPE, "PetscDS discretization id %d not recognized.", id); if (numFields > 1) { ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(refConSec,p,f,&cOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(refConSec,p,&cOff);CHKERRQ(ierr); } for (r = 0; r < cDof; r++) { rows[r] = cOff + r; } numCols = 0; { PetscInt aDof, aOff, j; if (numFields > 1) { ierr = PetscSectionGetFieldDof(refSection,parent,f,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetFieldOffset(refSection,parent,f,&aOff);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refSection,parent,&aDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(refSection,parent,&aOff);CHKERRQ(ierr); } for (j = 0; j < aDof; j++) { cols[numCols++] = aOff + j; } } ierr = PetscMalloc1(cDof*numCols,&refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr); /* transpose of constraint matrix */ ierr = MatGetValues(inj,numCols,cols,cDof,rows,refPointFieldMats[p-pRefStart][f]);CHKERRQ(ierr); } } *childrenMats = refPointFieldMats; ierr = PetscFree(rows);CHKERRQ(ierr); ierr = PetscFree(cols);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeRestoreChildrenMatrices_Injection" static PetscErrorCode DMPlexReferenceTreeRestoreChildrenMatrices_Injection(DM refTree, Mat inj, PetscScalar ****childrenMats) { PetscDS ds; PetscScalar ***refPointFieldMats; PetscInt numFields, pRefStart, pRefEnd, p, f; PetscSection refConSec, refSection; PetscErrorCode ierr; PetscFunctionBegin; refPointFieldMats = *childrenMats; *childrenMats = NULL; ierr = DMGetDS(refTree,&ds);CHKERRQ(ierr); ierr = DMGetDefaultSection(refTree,&refSection);CHKERRQ(ierr); ierr = PetscDSGetNumFields(ds,&numFields);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); for (p = pRefStart; p < pRefEnd; p++) { PetscInt parent, pDof, parentDof; ierr = DMPlexGetTreeParent(refTree,p,&parent,NULL);CHKERRQ(ierr); ierr = PetscSectionGetDof(refConSec,p,&pDof);CHKERRQ(ierr); ierr = PetscSectionGetDof(refSection,parent,&parentDof);CHKERRQ(ierr); if (!pDof || !parentDof || parent == p) continue; for (f = 0; f < numFields; f++) { PetscInt cDof; if (numFields > 1) { ierr = PetscSectionGetFieldDof(refConSec,p,f,&cDof);CHKERRQ(ierr); } else { ierr = PetscSectionGetDof(refConSec,p,&cDof);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats[p - pRefStart][f]);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats[p - pRefStart]);CHKERRQ(ierr); } ierr = PetscFree(refPointFieldMats);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexReferenceTreeGetInjector" static PetscErrorCode DMPlexReferenceTreeGetInjector(DM refTree,Mat *injRef) { Mat cMatRef; PetscObject injRefObj; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDefaultConstraints(refTree,NULL,&cMatRef);CHKERRQ(ierr); ierr = PetscObjectQuery((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",&injRefObj);CHKERRQ(ierr); *injRef = (Mat) injRefObj; if (!*injRef) { ierr = DMPlexComputeInjectorReferenceTree(refTree,injRef);CHKERRQ(ierr); ierr = PetscObjectCompose((PetscObject)cMatRef,"DMPlexComputeInjectorTree_refTree",(PetscObject)*injRef);CHKERRQ(ierr); /* there is now a reference in cMatRef, which should be the only one for symmetry with the above case */ ierr = PetscObjectDereference((PetscObject)*injRef);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTransferInjectorTree" 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) { PetscInt pStartF, pEndF, pStartC, pEndC, p, maxDof, numMulti; PetscSection globalCoarse, globalFine; PetscSection localCoarse, localFine, leafIndicesSec; PetscSection multiRootSec, rootIndicesSec; PetscInt *leafInds, *rootInds = NULL; const PetscInt *rootDegrees; PetscScalar *leafVals = NULL, *rootVals = NULL; PetscSF coarseToFineEmbedded; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr); ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafIndicesSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(leafIndicesSec,pStartF, pEndF);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(localFine,&maxDof);CHKERRQ(ierr); { /* winnow fine points that don't have global dofs out of the sf */ PetscInt l, nleaves, dof, cdof, numPointsWithDofs, offset, *pointsWithDofs, numIndices; const PetscInt *leaves; ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr); for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) { p = leaves ? leaves[l] : l; ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { numPointsWithDofs++; ierr = PetscSectionGetDof(localFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionSetDof(leafIndicesSec,p,dof + 1);CHKERRQ(ierr); } } ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr); ierr = PetscSectionSetUp(leafIndicesSec);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafIndicesSec,&numIndices);CHKERRQ(ierr); ierr = PetscMalloc1(gatheredIndices ? numIndices : (maxDof + 1),&leafInds);CHKERRQ(ierr); if (gatheredValues) {ierr = PetscMalloc1(numIndices,&leafVals);CHKERRQ(ierr);} for (l = 0, offset = 0; l < nleaves; l++) { p = leaves ? leaves[l] : l; ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { PetscInt off, gOff; PetscInt *pInd; PetscScalar *pVal = NULL; pointsWithDofs[offset++] = l; ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr); pInd = gatheredIndices ? (&leafInds[off + 1]) : leafInds; if (gatheredValues) { PetscInt i; pVal = &leafVals[off + 1]; for (i = 0; i < dof; i++) pVal[i] = 0.; } ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr); offsets[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localFine,p,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof + offsets[f]; } DMPlexGetIndicesPointFields_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } else { DMPlexGetIndicesPoint_Internal(localFine,p,gOff < 0 ? -(gOff + 1) : gOff,offsets,PETSC_FALSE,0,pInd);CHKERRQ(ierr); } if (gatheredValues) {ierr = VecGetValues(fineVec,dof,pInd,pVal);CHKERRQ(ierr);} } } ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr); } ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr); { /* there may be the case where an sf root has a parent: broadcast parents back to children */ MPI_Datatype threeInt; PetscMPIInt rank; PetscInt (*parentNodeAndIdCoarse)[3]; PetscInt (*parentNodeAndIdFine)[3]; PetscInt p, nleaves, nleavesToParents; PetscSF pointSF, sfToParents; const PetscInt *ilocal; const PetscSFNode *iremote; PetscSFNode *iremoteToParents; PetscInt *ilocalToParents; ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)coarse),&rank);CHKERRQ(ierr); ierr = MPI_Type_contiguous(3,MPIU_INT,&threeInt);CHKERRQ(ierr); ierr = MPI_Type_commit(&threeInt);CHKERRQ(ierr); ierr = PetscMalloc2(pEndC-pStartC,&parentNodeAndIdCoarse,pEndF-pStartF,&parentNodeAndIdFine);CHKERRQ(ierr); ierr = DMGetPointSF(coarse,&pointSF);CHKERRQ(ierr); ierr = PetscSFGetGraph(pointSF,NULL,&nleaves,&ilocal,&iremote);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt parent, childId; ierr = DMPlexGetTreeParent(coarse,p,&parent,&childId);CHKERRQ(ierr); parentNodeAndIdCoarse[p - pStartC][0] = rank; parentNodeAndIdCoarse[p - pStartC][1] = parent - pStartC; parentNodeAndIdCoarse[p - pStartC][2] = (p == parent) ? -1 : childId; if (nleaves > 0) { PetscInt leaf = -1; if (ilocal) { ierr = PetscFindInt(parent,nleaves,ilocal,&leaf);CHKERRQ(ierr); } else { leaf = p - pStartC; } if (leaf >= 0) { parentNodeAndIdCoarse[p - pStartC][0] = iremote[leaf].rank; parentNodeAndIdCoarse[p - pStartC][1] = iremote[leaf].index; } } } for (p = pStartF; p < pEndF; p++) { parentNodeAndIdFine[p - pStartF][0] = -1; parentNodeAndIdFine[p - pStartF][1] = -1; parentNodeAndIdFine[p - pStartF][2] = -1; } ierr = PetscSFBcastBegin(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr); ierr = PetscSFBcastEnd(coarseToFineEmbedded,threeInt,parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr); for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) { PetscInt dof; ierr = PetscSectionGetDof(leafIndicesSec,p,&dof);CHKERRQ(ierr); if (dof) { PetscInt off; ierr = PetscSectionGetOffset(leafIndicesSec,p,&off);CHKERRQ(ierr); if (gatheredIndices) { leafInds[off] = PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]); } else if (gatheredValues) { leafVals[off] = (PetscScalar) PetscMax(childIds[p-pStartF],parentNodeAndIdFine[p-pStartF][2]); } } if (parentNodeAndIdFine[p-pStartF][0] >= 0) { nleavesToParents++; } } ierr = PetscMalloc1(nleavesToParents,&ilocalToParents);CHKERRQ(ierr); ierr = PetscMalloc1(nleavesToParents,&iremoteToParents);CHKERRQ(ierr); for (p = pStartF, nleavesToParents = 0; p < pEndF; p++) { if (parentNodeAndIdFine[p-pStartF][0] >= 0) { ilocalToParents[nleavesToParents] = p - pStartF; iremoteToParents[nleavesToParents].rank = parentNodeAndIdFine[p-pStartF][0]; iremoteToParents[nleavesToParents].index = parentNodeAndIdFine[p-pStartF][1]; nleavesToParents++; } } ierr = PetscSFCreate(PetscObjectComm((PetscObject)coarse),&sfToParents);CHKERRQ(ierr); ierr = PetscSFSetGraph(sfToParents,pEndC-pStartC,nleavesToParents,ilocalToParents,PETSC_OWN_POINTER,iremoteToParents,PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr); coarseToFineEmbedded = sfToParents; ierr = PetscFree2(parentNodeAndIdCoarse,parentNodeAndIdFine);CHKERRQ(ierr); ierr = MPI_Type_free(&threeInt);CHKERRQ(ierr); } { /* winnow out coarse points that don't have dofs */ PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs; PetscSF sfDofsOnly; for (p = pStartC, numPointsWithDofs = 0; p < pEndC; p++) { ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { numPointsWithDofs++; } } ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr); for (p = pStartC, offset = 0; p < pEndC; p++) { ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { pointsWithDofs[offset++] = p - pStartC; } } ierr = PetscSFCreateEmbeddedSF(coarseToFineEmbedded, numPointsWithDofs, pointsWithDofs, &sfDofsOnly);CHKERRQ(ierr); ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr); coarseToFineEmbedded = sfDofsOnly; } /* communicate back to the coarse mesh which coarse points have children (that may require injection) */ ierr = PetscSFComputeDegreeBegin(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(coarseToFineEmbedded,&rootDegrees);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&multiRootSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(multiRootSec,pStartC,pEndC);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { ierr = PetscSectionSetDof(multiRootSec,p,rootDegrees[p-pStartC]);CHKERRQ(ierr); } ierr = PetscSectionSetUp(multiRootSec);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(multiRootSec,&numMulti);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootIndicesSec);CHKERRQ(ierr); { /* distribute the leaf section */ PetscSF multi, multiInv, indicesSF; PetscInt *remoteOffsets, numRootIndices; ierr = PetscSFGetMultiSF(coarseToFineEmbedded,&multi);CHKERRQ(ierr); ierr = PetscSFCreateInverseSF(multi,&multiInv);CHKERRQ(ierr); ierr = PetscSFDistributeSection(multiInv,leafIndicesSec,&remoteOffsets,rootIndicesSec);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(multiInv,leafIndicesSec,remoteOffsets,rootIndicesSec,&indicesSF);CHKERRQ(ierr); ierr = PetscFree(remoteOffsets);CHKERRQ(ierr); ierr = PetscSFDestroy(&multiInv);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(rootIndicesSec,&numRootIndices);CHKERRQ(ierr); if (gatheredIndices) { ierr = PetscMalloc1(numRootIndices,&rootInds);CHKERRQ(ierr); ierr = PetscSFBcastBegin(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr); ierr = PetscSFBcastEnd(indicesSF,MPIU_INT,leafInds,rootInds);CHKERRQ(ierr); } if (gatheredValues) { ierr = PetscMalloc1(numRootIndices,&rootVals);CHKERRQ(ierr); ierr = PetscSFBcastBegin(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr); ierr = PetscSFBcastEnd(indicesSF,MPIU_SCALAR,leafVals,rootVals);CHKERRQ(ierr); } ierr = PetscSFDestroy(&indicesSF);CHKERRQ(ierr); } ierr = PetscSectionDestroy(&leafIndicesSec);CHKERRQ(ierr); ierr = PetscFree(leafInds);CHKERRQ(ierr); ierr = PetscFree(leafVals);CHKERRQ(ierr); ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr); *rootMultiSec = multiRootSec; *multiLeafSec = rootIndicesSec; if (gatheredIndices) *gatheredIndices = rootInds; if (gatheredValues) *gatheredValues = rootVals; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexComputeInjectorTree" PetscErrorCode DMPlexComputeInjectorTree(DM coarse, DM fine, PetscSF coarseToFine, PetscInt *childIds, Mat mat) { DM refTree; PetscSection multiRootSec, rootIndicesSec; PetscSection globalCoarse, globalFine; PetscSection localCoarse, localFine; PetscSection cSecRef; PetscInt *rootIndices, *parentIndices, pRefStart, pRefEnd; Mat injRef; PetscInt numFields, maxDof; PetscInt pStartC, pEndC, pStartF, pEndF, p; PetscInt *offsets, *offsetsCopy, *rowOffsets; PetscLayout rowMap, colMap; PetscInt rowStart, rowEnd, colStart, colEnd, *nnzD, *nnzO; PetscScalar ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */ PetscErrorCode ierr; PetscFunctionBegin; /* get the templates for the fine-to-coarse injection from the reference tree */ ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr); ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr); ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr); ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr); ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr); { PetscInt maxFields = PetscMax(1,numFields) + 1; ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr); } ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,childIds,NULL,numFields,offsets,&multiRootSec,&rootIndicesSec,&rootIndices,NULL);CHKERRQ(ierr); ierr = PetscMalloc1(maxDof,&parentIndices);CHKERRQ(ierr); /* count indices */ ierr = MatGetLayouts(mat,&rowMap,&colMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr); ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr); ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr); ierr = PetscCalloc2(rowEnd-rowStart,&nnzD,rowEnd-rowStart,&nnzO);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) <= 0) continue; ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr); rowOffsets[0] = 0; offsetsCopy[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr); rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; } DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); } else { DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); rowOffsets[1] = offsetsCopy[0]; } ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr); ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr); leafEnd = leafStart + numLeaves; for (l = leafStart; l < leafEnd; l++) { PetscInt numIndices, childId, offset; const PetscInt *childIndices; ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr); childId = rootIndices[offset++]; childIndices = &rootIndices[offset]; numIndices--; if (childId == -1) { /* equivalent points: scatter */ PetscInt i; for (i = 0; i < numIndices; i++) { PetscInt colIndex = childIndices[i]; PetscInt rowIndex = parentIndices[i]; if (rowIndex < 0) continue; if (colIndex < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unconstrained fine and constrained coarse"); if (colIndex >= colStart && colIndex < colEnd) { nnzD[rowIndex - rowStart] = 1; } else { nnzO[rowIndex - rowStart] = 1; } } } else { PetscInt parentId, f, lim; ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr); lim = PetscMax(1,numFields); offsets[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof + offsets[f]; } } else { PetscInt cDof; ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr); offsets[1] = cDof; } for (f = 0; f < lim; f++) { PetscInt parentStart = rowOffsets[f], parentEnd = rowOffsets[f + 1]; PetscInt childStart = offsets[f], childEnd = offsets[f + 1]; PetscInt i, numD = 0, numO = 0; for (i = childStart; i < childEnd; i++) { PetscInt colIndex = childIndices[i]; if (colIndex < 0) continue; if (colIndex >= colStart && colIndex < colEnd) { numD++; } else { numO++; } } for (i = parentStart; i < parentEnd; i++) { PetscInt rowIndex = parentIndices[i]; if (rowIndex < 0) continue; nnzD[rowIndex - rowStart] += numD; nnzO[rowIndex - rowStart] += numO; } } } } } /* preallocate */ ierr = MatXAIJSetPreallocation(mat,1,nnzD,nnzO,NULL,NULL);CHKERRQ(ierr); ierr = PetscFree2(nnzD,nnzO);CHKERRQ(ierr); /* insert values */ ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) <= 0) continue; ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr); rowOffsets[0] = 0; offsetsCopy[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr); rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; } DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); } else { DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); rowOffsets[1] = offsetsCopy[0]; } ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr); ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr); leafEnd = leafStart + numLeaves; for (l = leafStart; l < leafEnd; l++) { PetscInt numIndices, childId, offset; const PetscInt *childIndices; ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr); childId = rootIndices[offset++]; childIndices = &rootIndices[offset]; numIndices--; if (childId == -1) { /* equivalent points: scatter */ PetscInt i; for (i = 0; i < numIndices; i++) { ierr = MatSetValue(mat,parentIndices[i],childIndices[i],1.,INSERT_VALUES);CHKERRQ(ierr); } } else { PetscInt parentId, f, lim; ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr); lim = PetscMax(1,numFields); offsets[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof + offsets[f]; } } else { PetscInt cDof; ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr); offsets[1] = cDof; } for (f = 0; f < lim; f++) { PetscScalar *childMat = &childrenMats[childId - pRefStart][f][0]; PetscInt *rowIndices = &parentIndices[rowOffsets[f]]; const PetscInt *colIndices = &childIndices[offsets[f]]; ierr = MatSetValues(mat,rowOffsets[f+1]-rowOffsets[f],rowIndices,offsets[f+1]-offsets[f],colIndices,childMat,INSERT_VALUES);CHKERRQ(ierr); } } } } ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr); ierr = PetscFree(parentIndices);CHKERRQ(ierr); ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr); ierr = PetscFree(rootIndices);CHKERRQ(ierr); ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr); ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTransferVecTree_Interpolate" static PetscErrorCode DMPlexTransferVecTree_Interpolate(DM coarse, Vec vecCoarseLocal, DM fine, Vec vecFine, PetscSF coarseToFine, PetscInt *cids, Vec grad, Vec cellGeom) { PetscDS ds; PetscSF coarseToFineEmbedded; PetscSection globalCoarse, globalFine; PetscSection localCoarse, localFine; PetscSection aSec, cSec; PetscSection rootValuesSec; PetscSection leafValuesSec; PetscScalar *rootValues, *leafValues; IS aIS; const PetscInt *anchors; Mat cMat; PetscInt numFields; PetscInt pStartC, pEndC, pStartF, pEndF, p, cellStart, cellEnd; PetscInt aStart, aEnd, cStart, cEnd; PetscInt *maxChildIds; PetscInt *offsets, *newOffsets, *offsetsCopy, *newOffsetsCopy, *rowOffsets, *numD, *numO; PetscFV fv = NULL; PetscInt dim, numFVcomps = -1, fvField = -1; DM cellDM = NULL, gradDM = NULL; const PetscScalar *cellGeomArray = NULL; const PetscScalar *gradArray = NULL; PetscErrorCode ierr; PetscFunctionBegin; ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr); ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(coarse,0,&cellStart,&cellEnd);CHKERRQ(ierr); ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr); ierr = DMGetCoordinateDim(coarse,&dim);CHKERRQ(ierr); { /* winnow fine points that don't have global dofs out of the sf */ PetscInt nleaves, l; const PetscInt *leaves; PetscInt dof, cdof, numPointsWithDofs, offset, *pointsWithDofs; ierr = PetscSFGetGraph(coarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr); for (l = 0, numPointsWithDofs = 0; l < nleaves; l++) { PetscInt p = leaves ? leaves[l] : l; ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { numPointsWithDofs++; } } ierr = PetscMalloc1(numPointsWithDofs,&pointsWithDofs);CHKERRQ(ierr); for (l = 0, offset = 0; l < nleaves; l++) { PetscInt p = leaves ? leaves[l] : l; ierr = PetscSectionGetDof(globalFine,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) > 0) { pointsWithDofs[offset++] = l; } } ierr = PetscSFCreateEmbeddedLeafSF(coarseToFine, numPointsWithDofs, pointsWithDofs, &coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(pointsWithDofs);CHKERRQ(ierr); } /* communicate back to the coarse mesh which coarse points have children (that may require interpolation) */ ierr = PetscMalloc1(pEndC-pStartC,&maxChildIds);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { maxChildIds[p - pStartC] = -2; } ierr = PetscSFReduceBegin(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr); ierr = PetscSFReduceEnd(coarseToFineEmbedded,MPIU_INT,cids,maxChildIds,MPIU_MAX);CHKERRQ(ierr); ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr); ierr = DMPlexGetAnchors(coarse,&aSec,&aIS);CHKERRQ(ierr); ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(coarse,&cSec,&cMat);CHKERRQ(ierr); ierr = PetscSectionGetChart(cSec,&cStart,&cEnd);CHKERRQ(ierr); /* create sections that will send to children the indices and matrices they will need to construct the interpolator */ ierr = PetscSectionCreate(PetscObjectComm((PetscObject)coarse),&rootValuesSec);CHKERRQ(ierr); ierr = PetscSectionSetChart(rootValuesSec,pStartC,pEndC);CHKERRQ(ierr); ierr = PetscSectionGetNumFields(localCoarse,&numFields);CHKERRQ(ierr); { PetscInt maxFields = PetscMax(1,numFields) + 1; ierr = PetscMalloc7(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&newOffsets,maxFields,&newOffsetsCopy,maxFields,&rowOffsets,maxFields,&numD,maxFields,&numO);CHKERRQ(ierr); } if (grad) { PetscInt i; ierr = VecGetDM(cellGeom,&cellDM);CHKERRQ(ierr); ierr = VecGetArrayRead(cellGeom,&cellGeomArray);CHKERRQ(ierr); ierr = VecGetDM(grad,&gradDM);CHKERRQ(ierr); ierr = VecGetArrayRead(grad,&gradArray);CHKERRQ(ierr); for (i = 0; i < PetscMax(1,numFields); i++) { PetscObject obj; PetscClassId id; ierr = DMGetField(coarse, i, &obj);CHKERRQ(ierr); ierr = PetscObjectGetClassId(obj,&id);CHKERRQ(ierr); if (id == PETSCFV_CLASSID) { fv = (PetscFV) obj; ierr = PetscFVGetNumComponents(fv,&numFVcomps);CHKERRQ(ierr); fvField = i; break; } } } for (p = pStartC; p < pEndC; p++) { /* count the sizes of the indices and matrices */ PetscInt dof; PetscInt maxChildId = maxChildIds[p - pStartC]; PetscInt numValues = 0; ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); if (dof < 0) { dof = -(dof + 1); } offsets[0] = 0; newOffsets[0] = 0; if (maxChildId >= 0) { /* this point has children (with dofs) that will need to be interpolated from the closure of p */ PetscInt *closure = NULL, closureSize, cl; ierr = DMPlexGetTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize; cl++) { /* get the closure */ PetscInt c = closure[2 * cl], clDof; ierr = PetscSectionGetDof(localCoarse,c,&clDof);CHKERRQ(ierr); numValues += clDof; } ierr = DMPlexRestoreTransitiveClosure(coarse,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); } else if (maxChildId == -1) { ierr = PetscSectionGetDof(localCoarse,p,&numValues);CHKERRQ(ierr); } /* we will pack the column indices with the field offsets */ if (maxChildId >= -1 && grad && p >= cellStart && p < cellEnd) { /* also send the centroid, and the gradient */ numValues += dim * (1 + numFVcomps); } ierr = PetscSectionSetDof(rootValuesSec,p,numValues);CHKERRQ(ierr); } ierr = PetscSectionSetUp(rootValuesSec);CHKERRQ(ierr); { PetscInt numRootValues; const PetscScalar *coarseArray; ierr = PetscSectionGetStorageSize(rootValuesSec,&numRootValues);CHKERRQ(ierr); ierr = PetscMalloc1(numRootValues,&rootValues);CHKERRQ(ierr); ierr = VecGetArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt numValues; PetscInt pValOff; PetscScalar *pVal; PetscInt maxChildId = maxChildIds[p - pStartC]; ierr = PetscSectionGetDof(rootValuesSec,p,&numValues);CHKERRQ(ierr); if (!numValues) { continue; } ierr = PetscSectionGetOffset(rootValuesSec,p,&pValOff);CHKERRQ(ierr); pVal = &(rootValues[pValOff]); if (maxChildId >= 0) { /* build an identity matrix, apply matrix constraints on the right */ PetscInt closureSize = numValues; ierr = DMPlexVecGetClosure(coarse,NULL,vecCoarseLocal,p,&closureSize,&pVal);CHKERRQ(ierr); } else if (maxChildId == -1) { PetscInt lDof, lOff, i; ierr = PetscSectionGetDof(localCoarse,p,&lDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(localCoarse,p,&lOff);CHKERRQ(ierr); for (i = 0; i < lDof; i++) pVal[i] = coarseArray[lOff + i]; } if (grad && p >= cellStart && p < cellEnd) { PetscFVCellGeom *cg; PetscScalar *gradVals = NULL; PetscInt i; pVal += (numValues - dim * (1 + numFVcomps)); ierr = DMPlexPointLocalRead(cellDM,p,cellGeomArray,(void *) &cg);CHKERRQ(ierr); for (i = 0; i < dim; i++) pVal[i] = cg->centroid[i]; pVal += dim; ierr = DMPlexPointGlobalRead(gradDM,p,gradArray,(void *) &gradVals);CHKERRQ(ierr); for (i = 0; i < dim * numFVcomps; i++) pVal[i] = gradVals[i]; } } ierr = VecRestoreArrayRead(vecCoarseLocal,&coarseArray);CHKERRQ(ierr); ierr = PetscFree(maxChildIds);CHKERRQ(ierr); } { PetscSF valuesSF; PetscInt *remoteOffsetsValues, numLeafValues; ierr = PetscSectionCreate(PetscObjectComm((PetscObject)fine),&leafValuesSec);CHKERRQ(ierr); ierr = PetscSFDistributeSection(coarseToFineEmbedded,rootValuesSec,&remoteOffsetsValues,leafValuesSec);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(coarseToFineEmbedded,rootValuesSec,remoteOffsetsValues,leafValuesSec,&valuesSF);CHKERRQ(ierr); ierr = PetscSFDestroy(&coarseToFineEmbedded);CHKERRQ(ierr); ierr = PetscFree(remoteOffsetsValues);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafValuesSec,&numLeafValues);CHKERRQ(ierr); ierr = PetscMalloc1(numLeafValues,&leafValues);CHKERRQ(ierr); ierr = PetscSFBcastBegin(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr); ierr = PetscSFBcastEnd(valuesSF,MPIU_SCALAR,rootValues,leafValues);CHKERRQ(ierr); ierr = PetscSFDestroy(&valuesSF);CHKERRQ(ierr); ierr = PetscFree(rootValues);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootValuesSec);CHKERRQ(ierr); } ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr); { PetscInt maxDof; PetscInt *rowIndices; DM refTree; PetscInt **refPointFieldN; PetscScalar ***refPointFieldMats; PetscSection refConSec, refAnSec; PetscInt pRefStart,pRefEnd,leafStart,leafEnd; PetscScalar *pointWork; ierr = PetscSectionGetMaxDof(globalFine,&maxDof);CHKERRQ(ierr); ierr = DMGetWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr); ierr = DMGetWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr); ierr = DMPlexGetReferenceTree(fine,&refTree);CHKERRQ(ierr); ierr = DMGetDS(fine,&ds);CHKERRQ(ierr); ierr = DMSetDS(refTree,ds);CHKERRQ(ierr); ierr = DMPlexReferenceTreeGetChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&refConSec,NULL);CHKERRQ(ierr); ierr = DMPlexGetAnchors(refTree,&refAnSec,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(refConSec,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = PetscSectionGetChart(leafValuesSec,&leafStart,&leafEnd);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(fine,0,&cellStart,&cellEnd);CHKERRQ(ierr); for (p = leafStart; p < leafEnd; p++) { PetscInt gDof, gcDof, gOff, lDof; PetscInt numValues, pValOff; PetscInt childId; const PetscScalar *pVal; const PetscScalar *fvGradData = NULL; ierr = PetscSectionGetDof(globalFine,p,&gDof);CHKERRQ(ierr); ierr = PetscSectionGetDof(localFine,p,&lDof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalFine,p,&gcDof);CHKERRQ(ierr); if ((gDof - gcDof) <= 0) { continue; } ierr = PetscSectionGetOffset(globalFine,p,&gOff);CHKERRQ(ierr); ierr = PetscSectionGetDof(leafValuesSec,p,&numValues);CHKERRQ(ierr); if (!numValues) continue; ierr = PetscSectionGetOffset(leafValuesSec,p,&pValOff);CHKERRQ(ierr); pVal = &leafValues[pValOff]; offsets[0] = 0; offsetsCopy[0] = 0; newOffsets[0] = 0; newOffsetsCopy[0] = 0; childId = cids[p - pStartF]; if (grad && p >= cellStart && p < cellEnd) { numValues -= (dim * (1 + numFVcomps)); fvGradData = &pVal[numValues]; } if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt rowDof; ierr = PetscSectionGetFieldDof(localFine,p,f,&rowDof);CHKERRQ(ierr); offsets[f + 1] = offsets[f] + rowDof; offsetsCopy[f + 1] = offsets[f + 1]; /* TODO: closure indices */ newOffsets[f + 1] = newOffsets[f] + ((childId == -1) ? rowDof : refPointFieldN[childId - pRefStart][f]); } ierr = DMPlexGetIndicesPointFields_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); } else { offsets[0] = 0; offsets[1] = lDof; newOffsets[0] = 0; newOffsets[1] = (childId == -1) ? lDof : refPointFieldN[childId - pRefStart][0]; ierr = DMPlexGetIndicesPoint_Internal(localFine,p,gOff,offsetsCopy,PETSC_FALSE,0,rowIndices);CHKERRQ(ierr); } if (childId == -1) { /* no child interpolation: one nnz per */ ierr = VecSetValues(vecFine,numValues,rowIndices,pVal,ADD_VALUES);CHKERRQ(ierr); } else { PetscInt f; for (f = 0; f < PetscMax(1,numFields); f++) { const PetscScalar *childMat = refPointFieldMats[childId - pRefStart][f]; PetscInt numRows = offsets[f+1] - offsets[f]; PetscInt numCols = newOffsets[f + 1] - newOffsets[f]; const PetscScalar *cVal = &pVal[newOffsets[f]]; PetscScalar *rVal = &pointWork[offsets[f]]; PetscInt i, j; #if 0 ierr = PetscInfo6(coarse,"field %D, numFields %D, childId %D, numRows %D, numCols %D, refPointFieldN %D\n",f,numFields,childId,numRows,numCols,refPointFieldN[childId - pRefStart][f]);CHKERRQ(ierr); #endif for (i = 0; i < numRows; i++) { PetscScalar val = 0.; for (j = 0; j < numCols; j++) { val += childMat[i * numCols + j] * cVal[j]; } rVal[i] = val; } if (f == fvField && p >= cellStart && p < cellEnd) { PetscReal centroid[3]; PetscScalar diff[3]; const PetscScalar *parentCentroid = &fvGradData[0]; const PetscScalar *gradient = &fvGradData[dim]; ierr = DMPlexComputeCellGeometryFVM(fine,p,NULL,centroid,NULL);CHKERRQ(ierr); for (i = 0; i < dim; i++) { diff[i] = centroid[i] - parentCentroid[i]; } for (i = 0; i < numFVcomps; i++) { PetscScalar val = 0.; for (j = 0; j < 3; j++) { val += gradient[dim * i + j] * diff[j]; } rVal[i] += val; } } ierr = VecSetValues(vecFine,numRows,&rowIndices[offsets[f]],rVal,ADD_VALUES);CHKERRQ(ierr); } } } ierr = DMPlexReferenceTreeRestoreChildrenMatrices(refTree,&refPointFieldMats,&refPointFieldN);CHKERRQ(ierr); ierr = DMRestoreWorkArray(fine,maxDof,PETSC_INT,&rowIndices);CHKERRQ(ierr); ierr = DMRestoreWorkArray(fine,maxDof,PETSC_SCALAR,&pointWork);CHKERRQ(ierr); } ierr = PetscFree(leafValues);CHKERRQ(ierr); ierr = PetscSectionDestroy(&leafValuesSec);CHKERRQ(ierr); ierr = PetscFree7(offsets,offsetsCopy,newOffsets,newOffsetsCopy,rowOffsets,numD,numO);CHKERRQ(ierr); ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTransferVecTree_Inject" static PetscErrorCode DMPlexTransferVecTree_Inject(DM fine, Vec vecFine, DM coarse, Vec vecCoarse, PetscSF coarseToFine, PetscInt *cids) { PetscDS ds; DM refTree; PetscSection multiRootSec, rootIndicesSec; PetscSection globalCoarse, globalFine; PetscSection localCoarse, localFine; PetscSection cSecRef; PetscInt *parentIndices, pRefStart, pRefEnd; PetscScalar *rootValues, *parentValues; Mat injRef; PetscInt numFields, maxDof; PetscInt pStartC, pEndC, pStartF, pEndF, p; PetscInt *offsets, *offsetsCopy, *rowOffsets; PetscLayout rowMap, colMap; PetscInt rowStart, rowEnd, colStart, colEnd; PetscScalar ***childrenMats=NULL ; /* gcc -O gives 'may be used uninitialized' warning'. Initializing to suppress this warning */ PetscErrorCode ierr; PetscFunctionBegin; /* get the templates for the fine-to-coarse injection from the reference tree */ ierr = VecSetOption(vecFine,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr); ierr = VecSetOption(vecCoarse,VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);CHKERRQ(ierr); ierr = DMPlexGetReferenceTree(coarse,&refTree);CHKERRQ(ierr); ierr = DMGetDS(coarse,&ds);CHKERRQ(ierr); ierr = DMSetDS(refTree,ds);CHKERRQ(ierr); ierr = DMGetDefaultConstraints(refTree,&cSecRef,NULL);CHKERRQ(ierr); ierr = PetscSectionGetChart(cSecRef,&pRefStart,&pRefEnd);CHKERRQ(ierr); ierr = DMPlexReferenceTreeGetInjector(refTree,&injRef);CHKERRQ(ierr); ierr = DMPlexGetChart(fine,&pStartF,&pEndF);CHKERRQ(ierr); ierr = DMGetDefaultSection(fine,&localFine);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(fine,&globalFine);CHKERRQ(ierr); ierr = PetscSectionGetNumFields(localFine,&numFields);CHKERRQ(ierr); ierr = DMPlexGetChart(coarse,&pStartC,&pEndC);CHKERRQ(ierr); ierr = DMGetDefaultSection(coarse,&localCoarse);CHKERRQ(ierr); ierr = DMGetDefaultGlobalSection(coarse,&globalCoarse);CHKERRQ(ierr); ierr = PetscSectionGetMaxDof(localCoarse,&maxDof);CHKERRQ(ierr); { PetscInt maxFields = PetscMax(1,numFields) + 1; ierr = PetscMalloc3(maxFields,&offsets,maxFields,&offsetsCopy,maxFields,&rowOffsets);CHKERRQ(ierr); } ierr = DMPlexTransferInjectorTree(coarse,fine,coarseToFine,cids,vecFine,numFields,offsets,&multiRootSec,&rootIndicesSec,NULL,&rootValues);CHKERRQ(ierr); ierr = PetscMalloc2(maxDof,&parentIndices,maxDof,&parentValues);CHKERRQ(ierr); /* count indices */ ierr = VecGetLayout(vecFine,&colMap);CHKERRQ(ierr); ierr = VecGetLayout(vecCoarse,&rowMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(rowMap);CHKERRQ(ierr); ierr = PetscLayoutSetUp(colMap);CHKERRQ(ierr); ierr = PetscLayoutGetRange(rowMap,&rowStart,&rowEnd);CHKERRQ(ierr); ierr = PetscLayoutGetRange(colMap,&colStart,&colEnd);CHKERRQ(ierr); /* insert values */ ierr = DMPlexReferenceTreeGetChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr); for (p = pStartC; p < pEndC; p++) { PetscInt numLeaves, leafStart, leafEnd, l, dof, cdof, gOff; ierr = PetscSectionGetDof(globalCoarse,p,&dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(globalCoarse,p,&cdof);CHKERRQ(ierr); if ((dof - cdof) <= 0) continue; ierr = PetscSectionGetOffset(globalCoarse,p,&gOff);CHKERRQ(ierr); rowOffsets[0] = 0; offsetsCopy[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(localCoarse,p,f,&fDof);CHKERRQ(ierr); rowOffsets[f + 1] = offsetsCopy[f + 1] = fDof + rowOffsets[f]; } DMPlexGetIndicesPointFields_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); } else { DMPlexGetIndicesPoint_Internal(localCoarse,p,gOff < 0 ? -(gOff + 1) : gOff,offsetsCopy,PETSC_FALSE,0,parentIndices);CHKERRQ(ierr); rowOffsets[1] = offsetsCopy[0]; } ierr = PetscSectionGetDof(multiRootSec,p,&numLeaves);CHKERRQ(ierr); ierr = PetscSectionGetOffset(multiRootSec,p,&leafStart);CHKERRQ(ierr); leafEnd = leafStart + numLeaves; for (l = leafStart; l < leafEnd; l++) { PetscInt numIndices, childId, offset; const PetscScalar *childValues; ierr = PetscSectionGetDof(rootIndicesSec,l,&numIndices);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootIndicesSec,l,&offset);CHKERRQ(ierr); childId = (PetscInt) PetscRealPart(rootValues[offset++]); childValues = &rootValues[offset]; numIndices--; if (childId == -2) { /* skip */ continue; } else if (childId == -1) { /* equivalent points: scatter */ ierr = VecSetValues(vecCoarse,numIndices,parentIndices,childValues,ADD_VALUES);CHKERRQ(ierr); } else { PetscInt parentId, f, lim; ierr = DMPlexGetTreeParent(refTree,childId,&parentId,NULL);CHKERRQ(ierr); lim = PetscMax(1,numFields); offsets[0] = 0; if (numFields) { PetscInt f; for (f = 0; f < numFields; f++) { PetscInt fDof; ierr = PetscSectionGetFieldDof(cSecRef,childId,f,&fDof);CHKERRQ(ierr); offsets[f + 1] = fDof + offsets[f]; } } else { PetscInt cDof; ierr = PetscSectionGetDof(cSecRef,childId,&cDof);CHKERRQ(ierr); offsets[1] = cDof; } for (f = 0; f < lim; f++) { PetscScalar *childMat = &childrenMats[childId - pRefStart][f][0]; PetscInt *rowIndices = &parentIndices[rowOffsets[f]]; PetscInt m = rowOffsets[f+1]-rowOffsets[f]; PetscInt n = offsets[f+1]-offsets[f]; PetscInt i, j; const PetscScalar *colValues = &childValues[offsets[f]]; for (i = 0; i < m; i++) { PetscScalar val = 0.; for (j = 0; j < n; j++) { val += childMat[n * i + j] * colValues[j]; } parentValues[i] = val; } ierr = VecSetValues(vecCoarse,m,rowIndices,parentValues,ADD_VALUES);CHKERRQ(ierr); } } } } ierr = PetscSectionDestroy(&multiRootSec);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootIndicesSec);CHKERRQ(ierr); ierr = PetscFree2(parentIndices,parentValues);CHKERRQ(ierr); ierr = DMPlexReferenceTreeRestoreChildrenMatrices_Injection(refTree,injRef,&childrenMats);CHKERRQ(ierr); ierr = PetscFree(rootValues);CHKERRQ(ierr); ierr = PetscFree3(offsets,offsetsCopy,rowOffsets);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexTransferVecTree" PetscErrorCode DMPlexTransferVecTree(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscSF sfIn, PetscSF sfOut, PetscInt *cidsIn, PetscInt *cidsOut, PetscBool useBCs, PetscReal time) { PetscErrorCode ierr; PetscFunctionBegin; if (sfIn) { Vec vecInLocal; DM dmGrad = NULL; Vec faceGeom = NULL, cellGeom = NULL, grad = NULL; ierr = DMGetLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr); ierr = VecSet(vecInLocal,0.0);CHKERRQ(ierr); { PetscInt numFields, i; ierr = DMGetNumFields(dmIn, &numFields);CHKERRQ(ierr); for (i = 0; i < numFields; i++) { PetscObject obj; PetscClassId classid; ierr = DMGetField(dmIn, i, &obj);CHKERRQ(ierr); ierr = PetscObjectGetClassId(obj, &classid);CHKERRQ(ierr); if (classid == PETSCFV_CLASSID) { ierr = DMPlexGetDataFVM(dmIn,(PetscFV)obj,&cellGeom,&faceGeom,&dmGrad);CHKERRQ(ierr); break; } } } if (useBCs) { ierr = DMPlexInsertBoundaryValues(dmIn,PETSC_TRUE,vecInLocal,time,faceGeom,cellGeom,NULL);CHKERRQ(ierr); } ierr = DMGlobalToLocalBegin(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr); ierr = DMGlobalToLocalEnd(dmIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr); if (dmGrad) { ierr = DMGetGlobalVector(dmGrad,&grad);CHKERRQ(ierr); ierr = DMPlexReconstructGradientsFVM(dmIn,vecInLocal,grad);CHKERRQ(ierr); } ierr = DMPlexTransferVecTree_Interpolate(dmIn,vecInLocal,dmOut,vecOut,sfIn,cidsIn,grad,cellGeom);CHKERRQ(ierr); ierr = DMRestoreLocalVector(dmIn,&vecInLocal);CHKERRQ(ierr); if (dmGrad) { ierr = DMRestoreGlobalVector(dmGrad,&grad);CHKERRQ(ierr); } } if (sfOut) { ierr = DMPlexTransferVecTree_Inject(dmIn,vecIn,dmOut,vecOut,sfOut,cidsOut);CHKERRQ(ierr); } PetscFunctionReturn(0); }