1e83e87a5Sjeremylt #include "../include/petscutils.h" 2e83e87a5Sjeremylt 3e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 4e83e87a5Sjeremylt // Convert PETSc MemType to libCEED MemType 5e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 6e83e87a5Sjeremylt CeedMemType MemTypeP2C(PetscMemType mtype) { 7e83e87a5Sjeremylt return PetscMemTypeDevice(mtype) ? CEED_MEM_DEVICE : CEED_MEM_HOST; 8e83e87a5Sjeremylt } 9e83e87a5Sjeremylt 10e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 11e83e87a5Sjeremylt // Utility function taken from petsc/src/dm/impls/plex/examples/tutorials/ex7.c 12e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 13e83e87a5Sjeremylt PetscErrorCode ProjectToUnitSphere(DM dm) { 14e83e87a5Sjeremylt Vec coordinates; 15e83e87a5Sjeremylt PetscScalar *coords; 16e83e87a5Sjeremylt PetscInt Nv, v, dim, d; 17e83e87a5Sjeremylt PetscErrorCode ierr; 18e83e87a5Sjeremylt 19e83e87a5Sjeremylt PetscFunctionBeginUser; 20e83e87a5Sjeremylt ierr = DMGetCoordinatesLocal(dm, &coordinates); CHKERRQ(ierr); 21e83e87a5Sjeremylt ierr = VecGetLocalSize(coordinates, &Nv); CHKERRQ(ierr); 22e83e87a5Sjeremylt ierr = VecGetBlockSize(coordinates, &dim); CHKERRQ(ierr); 23e83e87a5Sjeremylt Nv /= dim; 24e83e87a5Sjeremylt ierr = VecGetArray(coordinates, &coords); CHKERRQ(ierr); 25e83e87a5Sjeremylt for (v = 0; v < Nv; ++v) { 26e83e87a5Sjeremylt PetscReal r = 0.0; 27e83e87a5Sjeremylt 28e83e87a5Sjeremylt for (d = 0; d < dim; ++d) r += PetscSqr(PetscRealPart(coords[v*dim+d])); 29e83e87a5Sjeremylt r = PetscSqrtReal(r); 30e83e87a5Sjeremylt for (d = 0; d < dim; ++d) coords[v*dim+d] /= r; 31e83e87a5Sjeremylt } 32e83e87a5Sjeremylt ierr = VecRestoreArray(coordinates, &coords); CHKERRQ(ierr); 33e83e87a5Sjeremylt PetscFunctionReturn(0); 34e83e87a5Sjeremylt }; 35e83e87a5Sjeremylt 36e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 37*2c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 38*2c58efb6Sjeremylt // ----------------------------------------------------------------------------- 39*2c58efb6Sjeremylt // Transition from a value of "a" for x=0, to a value of "b" for x=1. Optionally 40*2c58efb6Sjeremylt // smooth -- see the commented versions at the end. 41*2c58efb6Sjeremylt static double step(const double a, const double b, double x) { 42*2c58efb6Sjeremylt if (x <= 0) return a; 43*2c58efb6Sjeremylt if (x >= 1) return b; 44*2c58efb6Sjeremylt return a + (b-a) * (x); 45*2c58efb6Sjeremylt } 46*2c58efb6Sjeremylt 47*2c58efb6Sjeremylt // 1D transformation at the right boundary 48*2c58efb6Sjeremylt static double right(const double eps, const double x) { 49*2c58efb6Sjeremylt return (x <= 0.5) ? (2-eps) * x : 1 + eps*(x-1); 50*2c58efb6Sjeremylt } 51*2c58efb6Sjeremylt 52*2c58efb6Sjeremylt // 1D transformation at the left boundary 53*2c58efb6Sjeremylt static double left(const double eps, const double x) { 54*2c58efb6Sjeremylt return 1-right(eps,1-x); 55*2c58efb6Sjeremylt } 56*2c58efb6Sjeremylt 57*2c58efb6Sjeremylt // Apply 3D Kershaw mesh transformation 58*2c58efb6Sjeremylt // The eps parameters are in (0, 1] 59*2c58efb6Sjeremylt // Uniform mesh is recovered for eps=1 60*2c58efb6Sjeremylt PetscErrorCode kershaw(DM dmorig, PetscScalar eps) { 61*2c58efb6Sjeremylt PetscErrorCode ierr; 62*2c58efb6Sjeremylt Vec coord; 63*2c58efb6Sjeremylt PetscInt ncoord; 64*2c58efb6Sjeremylt PetscScalar *c; 65*2c58efb6Sjeremylt 66*2c58efb6Sjeremylt PetscFunctionBeginUser; 67*2c58efb6Sjeremylt ierr = DMGetCoordinatesLocal(dmorig, &coord); CHKERRQ(ierr); 68*2c58efb6Sjeremylt ierr = VecGetLocalSize(coord, &ncoord); CHKERRQ(ierr); 69*2c58efb6Sjeremylt ierr = VecGetArray(coord, &c); CHKERRQ(ierr); 70*2c58efb6Sjeremylt 71*2c58efb6Sjeremylt for (PetscInt i = 0; i < ncoord; i += 3) { 72*2c58efb6Sjeremylt PetscScalar x = c[i], y = c[i+1], z = c[i+2]; 73*2c58efb6Sjeremylt PetscInt layer = x*6; 74*2c58efb6Sjeremylt PetscScalar lambda = (x-layer/6.0)*6; 75*2c58efb6Sjeremylt c[i] = x; 76*2c58efb6Sjeremylt 77*2c58efb6Sjeremylt switch (layer) { 78*2c58efb6Sjeremylt case 0: 79*2c58efb6Sjeremylt c[i+1] = left(eps, y); 80*2c58efb6Sjeremylt c[i+2] = left(eps, z); 81*2c58efb6Sjeremylt break; 82*2c58efb6Sjeremylt case 1: 83*2c58efb6Sjeremylt case 4: 84*2c58efb6Sjeremylt c[i+1] = step(left(eps, y), right(eps, y), lambda); 85*2c58efb6Sjeremylt c[i+2] = step(left(eps, z), right(eps, z), lambda); 86*2c58efb6Sjeremylt break; 87*2c58efb6Sjeremylt case 2: 88*2c58efb6Sjeremylt c[i+1] = step(right(eps, y), left(eps, y), lambda/2); 89*2c58efb6Sjeremylt c[i+2] = step(right(eps, z), left(eps, z), lambda/2); 90*2c58efb6Sjeremylt break; 91*2c58efb6Sjeremylt case 3: 92*2c58efb6Sjeremylt c[i+1] = step(right(eps, y), left(eps, y), (1+lambda)/2); 93*2c58efb6Sjeremylt c[i+2] = step(right(eps, z), left(eps, z), (1+lambda)/2); 94*2c58efb6Sjeremylt break; 95*2c58efb6Sjeremylt default: 96*2c58efb6Sjeremylt c[i+1] = right(eps, y); 97*2c58efb6Sjeremylt c[i+2] = right(eps, z); 98*2c58efb6Sjeremylt } 99*2c58efb6Sjeremylt } 100*2c58efb6Sjeremylt ierr = VecRestoreArray(coord, &c); CHKERRQ(ierr); 101*2c58efb6Sjeremylt PetscFunctionReturn(0); 102*2c58efb6Sjeremylt } 103*2c58efb6Sjeremylt 104*2c58efb6Sjeremylt // ----------------------------------------------------------------------------- 105e83e87a5Sjeremylt // PETSc FE Boilerplate 106e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 107e83e87a5Sjeremylt PetscErrorCode PetscFECreateByDegree(DM dm, PetscInt dim, PetscInt Nc, 108e83e87a5Sjeremylt PetscBool isSimplex, const char prefix[], 109e83e87a5Sjeremylt PetscInt order, PetscFE *fem) { 110e83e87a5Sjeremylt PetscQuadrature q, fq; 111e83e87a5Sjeremylt DM K; 112e83e87a5Sjeremylt PetscSpace P; 113e83e87a5Sjeremylt PetscDualSpace Q; 114e83e87a5Sjeremylt PetscInt quadPointsPerEdge; 115e83e87a5Sjeremylt PetscBool tensor = isSimplex ? PETSC_FALSE : PETSC_TRUE; 116e83e87a5Sjeremylt PetscErrorCode ierr; 117e83e87a5Sjeremylt 118e83e87a5Sjeremylt PetscFunctionBeginUser; 119e83e87a5Sjeremylt /* Create space */ 120e83e87a5Sjeremylt ierr = PetscSpaceCreate(PetscObjectComm((PetscObject) dm), &P); CHKERRQ(ierr); 121e83e87a5Sjeremylt ierr = PetscObjectSetOptionsPrefix((PetscObject) P, prefix); CHKERRQ(ierr); 122e83e87a5Sjeremylt ierr = PetscSpacePolynomialSetTensor(P, tensor); CHKERRQ(ierr); 123e83e87a5Sjeremylt ierr = PetscSpaceSetFromOptions(P); CHKERRQ(ierr); 124e83e87a5Sjeremylt ierr = PetscSpaceSetNumComponents(P, Nc); CHKERRQ(ierr); 125e83e87a5Sjeremylt ierr = PetscSpaceSetNumVariables(P, dim); CHKERRQ(ierr); 126e83e87a5Sjeremylt ierr = PetscSpaceSetDegree(P, order, order); CHKERRQ(ierr); 127e83e87a5Sjeremylt ierr = PetscSpaceSetUp(P); CHKERRQ(ierr); 128e83e87a5Sjeremylt ierr = PetscSpacePolynomialGetTensor(P, &tensor); CHKERRQ(ierr); 129e83e87a5Sjeremylt /* Create dual space */ 130e83e87a5Sjeremylt ierr = PetscDualSpaceCreate(PetscObjectComm((PetscObject) dm), &Q); 131e83e87a5Sjeremylt CHKERRQ(ierr); 132e83e87a5Sjeremylt ierr = PetscDualSpaceSetType(Q,PETSCDUALSPACELAGRANGE); CHKERRQ(ierr); 133e83e87a5Sjeremylt ierr = PetscObjectSetOptionsPrefix((PetscObject) Q, prefix); CHKERRQ(ierr); 134e83e87a5Sjeremylt ierr = PetscDualSpaceCreateReferenceCell(Q, dim, isSimplex, &K); CHKERRQ(ierr); 135e83e87a5Sjeremylt ierr = PetscDualSpaceSetDM(Q, K); CHKERRQ(ierr); 136e83e87a5Sjeremylt ierr = DMDestroy(&K); CHKERRQ(ierr); 137e83e87a5Sjeremylt ierr = PetscDualSpaceSetNumComponents(Q, Nc); CHKERRQ(ierr); 138e83e87a5Sjeremylt ierr = PetscDualSpaceSetOrder(Q, order); CHKERRQ(ierr); 139e83e87a5Sjeremylt ierr = PetscDualSpaceLagrangeSetTensor(Q, tensor); CHKERRQ(ierr); 140e83e87a5Sjeremylt ierr = PetscDualSpaceSetFromOptions(Q); CHKERRQ(ierr); 141e83e87a5Sjeremylt ierr = PetscDualSpaceSetUp(Q); CHKERRQ(ierr); 142e83e87a5Sjeremylt /* Create element */ 143e83e87a5Sjeremylt ierr = PetscFECreate(PetscObjectComm((PetscObject) dm), fem); CHKERRQ(ierr); 144e83e87a5Sjeremylt ierr = PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix); CHKERRQ(ierr); 145e83e87a5Sjeremylt ierr = PetscFESetFromOptions(*fem); CHKERRQ(ierr); 146e83e87a5Sjeremylt ierr = PetscFESetBasisSpace(*fem, P); CHKERRQ(ierr); 147e83e87a5Sjeremylt ierr = PetscFESetDualSpace(*fem, Q); CHKERRQ(ierr); 148e83e87a5Sjeremylt ierr = PetscFESetNumComponents(*fem, Nc); CHKERRQ(ierr); 149e83e87a5Sjeremylt ierr = PetscFESetUp(*fem); CHKERRQ(ierr); 150e83e87a5Sjeremylt ierr = PetscSpaceDestroy(&P); CHKERRQ(ierr); 151e83e87a5Sjeremylt ierr = PetscDualSpaceDestroy(&Q); CHKERRQ(ierr); 152e83e87a5Sjeremylt /* Create quadrature */ 153e83e87a5Sjeremylt quadPointsPerEdge = PetscMax(order + 1,1); 154e83e87a5Sjeremylt if (isSimplex) { 155e83e87a5Sjeremylt ierr = PetscDTStroudConicalQuadrature(dim, 1, quadPointsPerEdge, -1.0, 1.0, 156e83e87a5Sjeremylt &q); CHKERRQ(ierr); 157e83e87a5Sjeremylt ierr = PetscDTStroudConicalQuadrature(dim-1, 1, quadPointsPerEdge, -1.0, 1.0, 158e83e87a5Sjeremylt &fq); CHKERRQ(ierr); 159e83e87a5Sjeremylt } else { 160e83e87a5Sjeremylt ierr = PetscDTGaussTensorQuadrature(dim, 1, quadPointsPerEdge, -1.0, 1.0, 161e83e87a5Sjeremylt &q); CHKERRQ(ierr); 162e83e87a5Sjeremylt ierr = PetscDTGaussTensorQuadrature(dim-1, 1, quadPointsPerEdge, -1.0, 1.0, 163e83e87a5Sjeremylt &fq); CHKERRQ(ierr); 164e83e87a5Sjeremylt } 165e83e87a5Sjeremylt ierr = PetscFESetQuadrature(*fem, q); CHKERRQ(ierr); 166e83e87a5Sjeremylt ierr = PetscFESetFaceQuadrature(*fem, fq); CHKERRQ(ierr); 167e83e87a5Sjeremylt ierr = PetscQuadratureDestroy(&q); CHKERRQ(ierr); 168e83e87a5Sjeremylt ierr = PetscQuadratureDestroy(&fq); CHKERRQ(ierr); 169e83e87a5Sjeremylt 170e83e87a5Sjeremylt PetscFunctionReturn(0); 171e83e87a5Sjeremylt }; 172e83e87a5Sjeremylt 173e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 174e83e87a5Sjeremylt // Create BC label 175e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 176e83e87a5Sjeremylt static PetscErrorCode CreateBCLabel(DM dm, const char name[]) { 177e83e87a5Sjeremylt int ierr; 178e83e87a5Sjeremylt DMLabel label; 179e83e87a5Sjeremylt 180e83e87a5Sjeremylt PetscFunctionBeginUser; 181e83e87a5Sjeremylt 182e83e87a5Sjeremylt ierr = DMCreateLabel(dm, name); CHKERRQ(ierr); 183e83e87a5Sjeremylt ierr = DMGetLabel(dm, name, &label); CHKERRQ(ierr); 184e83e87a5Sjeremylt ierr = DMPlexMarkBoundaryFaces(dm, 1, label); CHKERRQ(ierr); 185e83e87a5Sjeremylt ierr = DMPlexLabelComplete(dm, label); CHKERRQ(ierr); 186e83e87a5Sjeremylt 187e83e87a5Sjeremylt PetscFunctionReturn(0); 188e83e87a5Sjeremylt }; 189e83e87a5Sjeremylt 190e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 191e83e87a5Sjeremylt // This function sets up a DM for a given degree 192e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 193e83e87a5Sjeremylt PetscErrorCode SetupDMByDegree(DM dm, PetscInt degree, PetscInt ncompu, 194e83e87a5Sjeremylt PetscInt dim, bool enforcebc, BCFunction bcsfunc) { 195e83e87a5Sjeremylt PetscInt ierr, marker_ids[1] = {1}; 196e83e87a5Sjeremylt PetscFE fe; 197e83e87a5Sjeremylt 198e83e87a5Sjeremylt PetscFunctionBeginUser; 199e83e87a5Sjeremylt 200e83e87a5Sjeremylt // Setup FE 201e83e87a5Sjeremylt ierr = PetscFECreateByDegree(dm, dim, ncompu, PETSC_FALSE, NULL, degree, &fe); 202e83e87a5Sjeremylt CHKERRQ(ierr); 203e83e87a5Sjeremylt ierr = DMSetFromOptions(dm); CHKERRQ(ierr); 204e83e87a5Sjeremylt ierr = DMAddField(dm, NULL, (PetscObject)fe); CHKERRQ(ierr); 205e83e87a5Sjeremylt 206e83e87a5Sjeremylt // Setup DM 207e83e87a5Sjeremylt ierr = DMCreateDS(dm); CHKERRQ(ierr); 208e83e87a5Sjeremylt if (enforcebc) { 209e83e87a5Sjeremylt PetscBool hasLabel; 210e83e87a5Sjeremylt DMHasLabel(dm, "marker", &hasLabel); 211e83e87a5Sjeremylt if (!hasLabel) {CreateBCLabel(dm, "marker");} 212e83e87a5Sjeremylt ierr = DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", "marker", 0, 0, NULL, 213e83e87a5Sjeremylt (void(*)(void))bcsfunc, NULL, 1, marker_ids, NULL); 214e83e87a5Sjeremylt CHKERRQ(ierr); 215e83e87a5Sjeremylt } 216e83e87a5Sjeremylt ierr = DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL); 217e83e87a5Sjeremylt CHKERRQ(ierr); 218e83e87a5Sjeremylt ierr = PetscFEDestroy(&fe); CHKERRQ(ierr); 219e83e87a5Sjeremylt 220e83e87a5Sjeremylt PetscFunctionReturn(0); 221e83e87a5Sjeremylt }; 222e83e87a5Sjeremylt 223e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 224e83e87a5Sjeremylt // Utility function - essential BC dofs are encoded in closure indices as -(i+1) 225e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 226e83e87a5Sjeremylt PetscInt Involute(PetscInt i) { 227e83e87a5Sjeremylt return i >= 0 ? i : -(i + 1); 228e83e87a5Sjeremylt }; 229e83e87a5Sjeremylt 230e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 231e83e87a5Sjeremylt // Get CEED restriction data from DMPlex 232e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 233e83e87a5Sjeremylt PetscErrorCode CreateRestrictionFromPlex(Ceed ceed, DM dm, CeedInt P, 234e83e87a5Sjeremylt CeedInt topodim, CeedInt height, DMLabel domainLabel, CeedInt value, 235e83e87a5Sjeremylt CeedElemRestriction *Erestrict) { 236e83e87a5Sjeremylt PetscSection section; 237e83e87a5Sjeremylt PetscInt p, Nelem, Ndof, *erestrict, eoffset, nfields, dim, depth; 238e83e87a5Sjeremylt DMLabel depthLabel; 239e83e87a5Sjeremylt IS depthIS, iterIS; 240e83e87a5Sjeremylt Vec Uloc; 241e83e87a5Sjeremylt const PetscInt *iterIndices; 242e83e87a5Sjeremylt PetscErrorCode ierr; 243e83e87a5Sjeremylt 244e83e87a5Sjeremylt PetscFunctionBeginUser; 245e83e87a5Sjeremylt 246e83e87a5Sjeremylt ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); 247e83e87a5Sjeremylt dim -= height; 248e83e87a5Sjeremylt ierr = DMGetLocalSection(dm, §ion); CHKERRQ(ierr); 249e83e87a5Sjeremylt ierr = PetscSectionGetNumFields(section, &nfields); CHKERRQ(ierr); 250e83e87a5Sjeremylt PetscInt ncomp[nfields], fieldoff[nfields+1]; 251e83e87a5Sjeremylt fieldoff[0] = 0; 252e83e87a5Sjeremylt for (PetscInt f = 0; f < nfields; f++) { 253e83e87a5Sjeremylt ierr = PetscSectionGetFieldComponents(section, f, &ncomp[f]); CHKERRQ(ierr); 254e83e87a5Sjeremylt fieldoff[f+1] = fieldoff[f] + ncomp[f]; 255e83e87a5Sjeremylt } 256e83e87a5Sjeremylt 257e83e87a5Sjeremylt ierr = DMPlexGetDepth(dm, &depth); CHKERRQ(ierr); 258e83e87a5Sjeremylt ierr = DMPlexGetDepthLabel(dm, &depthLabel); CHKERRQ(ierr); 259e83e87a5Sjeremylt ierr = DMLabelGetStratumIS(depthLabel, depth - height, &depthIS); CHKERRQ(ierr); 260e83e87a5Sjeremylt if (domainLabel) { 261e83e87a5Sjeremylt IS domainIS; 262e83e87a5Sjeremylt ierr = DMLabelGetStratumIS(domainLabel, value, &domainIS); CHKERRQ(ierr); 263e83e87a5Sjeremylt if (domainIS) { // domainIS is non-empty 264e83e87a5Sjeremylt ierr = ISIntersect(depthIS, domainIS, &iterIS); CHKERRQ(ierr); 265e83e87a5Sjeremylt ierr = ISDestroy(&domainIS); CHKERRQ(ierr); 266e83e87a5Sjeremylt } else { // domainIS is NULL (empty) 267e83e87a5Sjeremylt iterIS = NULL; 268e83e87a5Sjeremylt } 269e83e87a5Sjeremylt ierr = ISDestroy(&depthIS); CHKERRQ(ierr); 270e83e87a5Sjeremylt } else { 271e83e87a5Sjeremylt iterIS = depthIS; 272e83e87a5Sjeremylt } 273e83e87a5Sjeremylt if (iterIS) { 274e83e87a5Sjeremylt ierr = ISGetLocalSize(iterIS, &Nelem); CHKERRQ(ierr); 275e83e87a5Sjeremylt ierr = ISGetIndices(iterIS, &iterIndices); CHKERRQ(ierr); 276e83e87a5Sjeremylt } else { 277e83e87a5Sjeremylt Nelem = 0; 278e83e87a5Sjeremylt iterIndices = NULL; 279e83e87a5Sjeremylt } 280e83e87a5Sjeremylt ierr = PetscMalloc1(Nelem*PetscPowInt(P, topodim), &erestrict); CHKERRQ(ierr); 281e83e87a5Sjeremylt for (p = 0, eoffset = 0; p < Nelem; p++) { 282e83e87a5Sjeremylt PetscInt c = iterIndices[p]; 283e83e87a5Sjeremylt PetscInt numindices, *indices, nnodes; 284e83e87a5Sjeremylt ierr = DMPlexGetClosureIndices(dm, section, section, c, PETSC_TRUE, 285e83e87a5Sjeremylt &numindices, &indices, NULL, NULL); 286e83e87a5Sjeremylt CHKERRQ(ierr); 287e83e87a5Sjeremylt bool flip = false; 288e83e87a5Sjeremylt if (height > 0) { 289e83e87a5Sjeremylt PetscInt numCells, numFaces, start = -1; 290e83e87a5Sjeremylt const PetscInt *orients, *faces, *cells; 291e83e87a5Sjeremylt ierr = DMPlexGetSupport(dm, c, &cells); CHKERRQ(ierr); 292e83e87a5Sjeremylt ierr = DMPlexGetSupportSize(dm, c, &numCells); CHKERRQ(ierr); 293e83e87a5Sjeremylt if (numCells != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, 294e83e87a5Sjeremylt "Expected one cell in support of exterior face, but got %D cells", 295e83e87a5Sjeremylt numCells); 296e83e87a5Sjeremylt ierr = DMPlexGetCone(dm, cells[0], &faces); CHKERRQ(ierr); 297e83e87a5Sjeremylt ierr = DMPlexGetConeSize(dm, cells[0], &numFaces); CHKERRQ(ierr); 298e83e87a5Sjeremylt for (PetscInt i=0; i<numFaces; i++) {if (faces[i] == c) start = i;} 299e83e87a5Sjeremylt if (start < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, 300e83e87a5Sjeremylt "Could not find face %D in cone of its support", 301e83e87a5Sjeremylt c); 302e83e87a5Sjeremylt ierr = DMPlexGetConeOrientation(dm, cells[0], &orients); CHKERRQ(ierr); 303e83e87a5Sjeremylt if (orients[start] < 0) flip = true; 304e83e87a5Sjeremylt } 305e83e87a5Sjeremylt if (numindices % fieldoff[nfields]) SETERRQ1(PETSC_COMM_SELF, 306e83e87a5Sjeremylt PETSC_ERR_ARG_INCOMP, "Number of closure indices not compatible with Cell %D", 307e83e87a5Sjeremylt c); 308e83e87a5Sjeremylt nnodes = numindices / fieldoff[nfields]; 309e83e87a5Sjeremylt for (PetscInt i = 0; i < nnodes; i++) { 310e83e87a5Sjeremylt PetscInt ii = i; 311e83e87a5Sjeremylt if (flip) { 312e83e87a5Sjeremylt if (P == nnodes) ii = nnodes - 1 - i; 313e83e87a5Sjeremylt else if (P*P == nnodes) { 314e83e87a5Sjeremylt PetscInt row = i / P, col = i % P; 315e83e87a5Sjeremylt ii = row + col * P; 316e83e87a5Sjeremylt } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, 317e83e87a5Sjeremylt "No support for flipping point with %D nodes != P (%D) or P^2", 318e83e87a5Sjeremylt nnodes, P); 319e83e87a5Sjeremylt } 320e83e87a5Sjeremylt // Check that indices are blocked by node and thus can be coalesced as a single field with 321e83e87a5Sjeremylt // fieldoff[nfields] = sum(ncomp) components. 322e83e87a5Sjeremylt for (PetscInt f = 0; f < nfields; f++) { 323e83e87a5Sjeremylt for (PetscInt j = 0; j < ncomp[f]; j++) { 324e83e87a5Sjeremylt if (Involute(indices[fieldoff[f]*nnodes + ii*ncomp[f] + j]) 325e83e87a5Sjeremylt != Involute(indices[ii*ncomp[0]]) + fieldoff[f] + j) 326e83e87a5Sjeremylt SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, 327e83e87a5Sjeremylt "Cell %D closure indices not interlaced for node %D field %D component %D", 328e83e87a5Sjeremylt c, ii, f, j); 329e83e87a5Sjeremylt } 330e83e87a5Sjeremylt } 331e83e87a5Sjeremylt // Essential boundary conditions are encoded as -(loc+1), but we don't care so we decode. 332e83e87a5Sjeremylt PetscInt loc = Involute(indices[ii*ncomp[0]]); 333e83e87a5Sjeremylt erestrict[eoffset++] = loc; 334e83e87a5Sjeremylt } 335e83e87a5Sjeremylt ierr = DMPlexRestoreClosureIndices(dm, section, section, c, PETSC_TRUE, 336e83e87a5Sjeremylt &numindices, &indices, NULL, NULL); 337e83e87a5Sjeremylt CHKERRQ(ierr); 338e83e87a5Sjeremylt } 339e83e87a5Sjeremylt if (eoffset != Nelem*PetscPowInt(P, topodim)) 340e83e87a5Sjeremylt SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, 341e83e87a5Sjeremylt "ElemRestriction of size (%D,%D) initialized %D nodes", Nelem, 342e83e87a5Sjeremylt PetscPowInt(P, topodim),eoffset); 343e83e87a5Sjeremylt if (iterIS) { 344e83e87a5Sjeremylt ierr = ISRestoreIndices(iterIS, &iterIndices); CHKERRQ(ierr); 345e83e87a5Sjeremylt } 346e83e87a5Sjeremylt ierr = ISDestroy(&iterIS); CHKERRQ(ierr); 347e83e87a5Sjeremylt 348e83e87a5Sjeremylt ierr = DMGetLocalVector(dm, &Uloc); CHKERRQ(ierr); 349e83e87a5Sjeremylt ierr = VecGetLocalSize(Uloc, &Ndof); CHKERRQ(ierr); 350e83e87a5Sjeremylt ierr = DMRestoreLocalVector(dm, &Uloc); CHKERRQ(ierr); 351e83e87a5Sjeremylt CeedElemRestrictionCreate(ceed, Nelem, PetscPowInt(P, topodim), 352e83e87a5Sjeremylt fieldoff[nfields], 353e83e87a5Sjeremylt 1, Ndof, CEED_MEM_HOST, CEED_COPY_VALUES, erestrict, 354e83e87a5Sjeremylt Erestrict); 355e83e87a5Sjeremylt ierr = PetscFree(erestrict); CHKERRQ(ierr); 356e83e87a5Sjeremylt PetscFunctionReturn(0); 357e83e87a5Sjeremylt }; 358e83e87a5Sjeremylt 359e83e87a5Sjeremylt // ----------------------------------------------------------------------------- 360