#include /*I "petscdmplex.h" I*/ #include /*I "petscmat.h" I*/ #include static PetscErrorCode DMPlexCreateOrderingClosure_Static(DM dm, PetscInt numPoints, const PetscInt pperm[], PetscInt **clperm, PetscInt **invclperm) { PetscInt *perm, *iperm; PetscInt depth, d, pStart, pEnd, fStart, fMax, fEnd, p; PetscFunctionBegin; PetscCall(DMPlexGetDepth(dm, &depth)); PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(PetscMalloc1(pEnd - pStart, &perm)); PetscCall(PetscMalloc1(pEnd - pStart, &iperm)); for (p = pStart; p < pEnd; ++p) iperm[p] = -1; for (d = depth; d > 0; --d) { PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); PetscCall(DMPlexGetDepthStratum(dm, d - 1, &fStart, &fEnd)); fMax = fStart; for (p = pStart; p < pEnd; ++p) { const PetscInt *cone; PetscInt point, coneSize, c; if (d == depth) { perm[p] = pperm[p]; iperm[pperm[p]] = p; } point = perm[p]; PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); PetscCall(DMPlexGetCone(dm, point, &cone)); for (c = 0; c < coneSize; ++c) { const PetscInt oldc = cone[c]; const PetscInt newc = iperm[oldc]; if (newc < 0) { perm[fMax] = oldc; iperm[oldc] = fMax++; } } } PetscCheck(fMax == fEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of depth %" PetscInt_FMT " faces %" PetscInt_FMT " does not match permuted number %" PetscInt_FMT, d, fEnd - fStart, fMax - fStart); } *clperm = perm; *invclperm = iperm; PetscFunctionReturn(PETSC_SUCCESS); } /*@C DMPlexGetOrdering - Calculate a reordering of the mesh Collective Input Parameters: + dm - The `DMPLEX` object . otype - type of reordering, see `MatOrderingType` - label - [Optional] Label used to segregate ordering into sets, or `NULL` Output Parameter: . perm - The point permutation as an `IS`, `perm`[old point number] = new point number Level: intermediate Note: The label is used to group sets of points together by label value. This makes it easy to reorder a mesh which has different types of cells, and then loop over each set of reordered cells for assembly. .seealso: `DMPLEX`, `DMPlexPermute()`, `MatOrderingType`, `MatGetOrdering()` @*/ PetscErrorCode DMPlexGetOrdering(DM dm, MatOrderingType otype, DMLabel label, IS *perm) { PetscInt numCells = 0; PetscInt *start = NULL, *adjacency = NULL, *cperm, *clperm = NULL, *invclperm = NULL, *mask, *xls, pStart, pEnd, c, i; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscAssertPointer(perm, 4); PetscCall(DMPlexCreateNeighborCSR(dm, 0, &numCells, &start, &adjacency)); PetscCall(PetscMalloc3(numCells, &cperm, numCells, &mask, numCells * 2, &xls)); if (numCells) { /* Shift for Fortran numbering */ for (i = 0; i < start[numCells]; ++i) ++adjacency[i]; for (i = 0; i <= numCells; ++i) ++start[i]; PetscCall(SPARSEPACKgenrcm(&numCells, start, adjacency, cperm, mask, xls)); } PetscCall(PetscFree(start)); PetscCall(PetscFree(adjacency)); /* Shift for Fortran numbering */ for (c = 0; c < numCells; ++c) --cperm[c]; /* Segregate */ if (label) { IS valueIS; const PetscInt *valuesTmp; PetscInt *values; PetscInt numValues, numPoints = 0; PetscInt *sperm, *vsize, *voff, v; // Can't directly sort the valueIS, since it is a view into the DMLabel PetscCall(DMLabelGetValueIS(label, &valueIS)); PetscCall(ISGetLocalSize(valueIS, &numValues)); PetscCall(ISGetIndices(valueIS, &valuesTmp)); PetscCall(PetscCalloc4(numCells, &sperm, numValues, &values, numValues, &vsize, numValues + 1, &voff)); PetscCall(PetscArraycpy(values, valuesTmp, numValues)); PetscCall(PetscSortInt(numValues, values)); PetscCall(ISRestoreIndices(valueIS, &valuesTmp)); PetscCall(ISDestroy(&valueIS)); for (v = 0; v < numValues; ++v) { PetscCall(DMLabelGetStratumSize(label, values[v], &vsize[v])); if (v < numValues - 1) voff[v + 2] += vsize[v] + voff[v + 1]; numPoints += vsize[v]; } PetscCheck(numPoints == numCells, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label only covers %" PetscInt_FMT " cells != %" PetscInt_FMT " total cells", numPoints, numCells); for (c = 0; c < numCells; ++c) { const PetscInt oldc = cperm[c]; PetscInt val, vloc; PetscCall(DMLabelGetValue(label, oldc, &val)); PetscCheck(val != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " not present in label", oldc); PetscCall(PetscFindInt(val, numValues, values, &vloc)); PetscCheck(vloc >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Value %" PetscInt_FMT " not present label", val); sperm[voff[vloc + 1]++] = oldc; } for (v = 0; v < numValues; ++v) PetscCheck(voff[v + 1] - voff[v] == vsize[v], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of %" PetscInt_FMT " values found is %" PetscInt_FMT " != %" PetscInt_FMT, values[v], voff[v + 1] - voff[v], vsize[v]); PetscCall(PetscArraycpy(cperm, sperm, numCells)); PetscCall(PetscFree4(sperm, values, vsize, voff)); } /* Construct closure */ PetscCall(DMPlexCreateOrderingClosure_Static(dm, numCells, cperm, &clperm, &invclperm)); PetscCall(PetscFree3(cperm, mask, xls)); PetscCall(PetscFree(clperm)); /* Invert permutation */ PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, invclperm, PETSC_OWN_POINTER, perm)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ DMPlexGetOrdering1D - Reorder the vertices so that the mesh is in a line Collective Input Parameter: . dm - The `DMPLEX` object Output Parameter: . perm - The point permutation as an `IS`, `perm`[old point number] = new point number Level: intermediate .seealso: `DMPLEX`, `DMPlexGetOrdering()`, `DMPlexPermute()`, `MatGetOrdering()` @*/ PetscErrorCode DMPlexGetOrdering1D(DM dm, IS *perm) { PetscInt *points; const PetscInt *support, *cone; PetscInt dim, pStart, pEnd, cStart, cEnd, c, vStart, vEnd, v, suppSize, lastCell = 0; PetscFunctionBegin; PetscCall(DMGetDimension(dm, &dim)); PetscCheck(dim == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input mesh must be one dimensional, not %" PetscInt_FMT, dim); PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); PetscCall(PetscMalloc1(pEnd - pStart, &points)); for (c = cStart; c < cEnd; ++c) points[c] = c; for (v = vStart; v < vEnd; ++v) points[v] = v; for (v = vStart; v < vEnd; ++v) { PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); PetscCall(DMPlexGetSupport(dm, v, &support)); if (suppSize == 1) { lastCell = support[0]; break; } } if (v < vEnd) { PetscInt pos = cEnd; points[v] = pos++; while (lastCell >= cStart) { PetscCall(DMPlexGetCone(dm, lastCell, &cone)); if (cone[0] == v) v = cone[1]; else v = cone[0]; PetscCall(DMPlexGetSupport(dm, v, &support)); PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); if (suppSize == 1) { lastCell = -1; } else { if (support[0] == lastCell) lastCell = support[1]; else lastCell = support[0]; } points[v] = pos++; } PetscCheck(pos == pEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Last vertex was %" PetscInt_FMT ", not %" PetscInt_FMT, pos, pEnd); } PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, points, PETSC_OWN_POINTER, perm)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode DMPlexRemapCoordinates_Private(IS perm, PetscSection cs, Vec coordinates, PetscSection *csNew, Vec *coordinatesNew) { PetscScalar *coords, *coordsNew; const PetscInt *pperm; PetscInt pStart, pEnd, p; const char *name; PetscFunctionBegin; PetscCall(PetscSectionPermute(cs, perm, csNew)); PetscCall(VecDuplicate(coordinates, coordinatesNew)); PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); PetscCall(PetscObjectSetName((PetscObject)*coordinatesNew, name)); PetscCall(VecGetArray(coordinates, &coords)); PetscCall(VecGetArray(*coordinatesNew, &coordsNew)); PetscCall(PetscSectionGetChart(*csNew, &pStart, &pEnd)); PetscCall(ISGetIndices(perm, &pperm)); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; PetscCall(PetscSectionGetDof(*csNew, p, &dof)); PetscCall(PetscSectionGetOffset(cs, p, &off)); PetscCall(PetscSectionGetOffset(*csNew, pperm[p], &offNew)); for (d = 0; d < dof; ++d) coordsNew[offNew + d] = coords[off + d]; } PetscCall(ISRestoreIndices(perm, &pperm)); PetscCall(VecRestoreArray(coordinates, &coords)); PetscCall(VecRestoreArray(*coordinatesNew, &coordsNew)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ DMPlexPermute - Reorder the mesh according to the input permutation Collective Input Parameters: + dm - The `DMPLEX` object - perm - The point permutation, `perm`[old point number] = new point number Output Parameter: . pdm - The permuted `DM` Level: intermediate .seealso: `DMPLEX`, `MatPermute()` @*/ PetscErrorCode DMPlexPermute(DM dm, IS perm, DM *pdm) { DM_Plex *plex = (DM_Plex *)dm->data, *plexNew; PetscInt dim, cdim; const char *name; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(perm, IS_CLASSID, 2); PetscAssertPointer(pdm, 3); PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), pdm)); PetscCall(DMSetType(*pdm, DMPLEX)); PetscCall(PetscObjectGetName((PetscObject)dm, &name)); PetscCall(PetscObjectSetName((PetscObject)*pdm, name)); PetscCall(DMGetDimension(dm, &dim)); PetscCall(DMSetDimension(*pdm, dim)); PetscCall(DMGetCoordinateDim(dm, &cdim)); PetscCall(DMSetCoordinateDim(*pdm, cdim)); PetscCall(DMCopyDisc(dm, *pdm)); if (dm->localSection) { PetscSection section, sectionNew; PetscCall(DMGetLocalSection(dm, §ion)); PetscCall(PetscSectionPermute(section, perm, §ionNew)); PetscCall(DMSetLocalSection(*pdm, sectionNew)); PetscCall(PetscSectionDestroy(§ionNew)); } plexNew = (DM_Plex *)(*pdm)->data; /* Ignore ltogmap, ltogmapb */ /* Ignore sf, sectionSF */ /* Ignore globalVertexNumbers, globalCellNumbers */ /* Reorder labels */ { PetscInt numLabels, l; DMLabel label, labelNew; PetscCall(DMGetNumLabels(dm, &numLabels)); for (l = 0; l < numLabels; ++l) { PetscCall(DMGetLabelByNum(dm, l, &label)); PetscCall(DMLabelPermute(label, perm, &labelNew)); PetscCall(DMAddLabel(*pdm, labelNew)); PetscCall(DMLabelDestroy(&labelNew)); } PetscCall(DMGetLabel(*pdm, "depth", &(*pdm)->depthLabel)); if (plex->subpointMap) PetscCall(DMLabelPermute(plex->subpointMap, perm, &plexNew->subpointMap)); } if ((*pdm)->celltypeLabel) { DMLabel ctLabel; // Reset label for fast lookup PetscCall(DMPlexGetCellTypeLabel(*pdm, &ctLabel)); PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); } /* Reorder topology */ { const PetscInt *pperm; PetscInt n, pStart, pEnd, p; PetscCall(PetscSectionDestroy(&plexNew->coneSection)); PetscCall(PetscSectionPermute(plex->coneSection, perm, &plexNew->coneSection)); PetscCall(PetscSectionGetStorageSize(plexNew->coneSection, &n)); PetscCall(PetscMalloc1(n, &plexNew->cones)); PetscCall(PetscMalloc1(n, &plexNew->coneOrientations)); PetscCall(ISGetIndices(perm, &pperm)); PetscCall(PetscSectionGetChart(plex->coneSection, &pStart, &pEnd)); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; PetscCall(PetscSectionGetDof(plexNew->coneSection, pperm[p], &dof)); PetscCall(PetscSectionGetOffset(plex->coneSection, p, &off)); PetscCall(PetscSectionGetOffset(plexNew->coneSection, pperm[p], &offNew)); for (d = 0; d < dof; ++d) { plexNew->cones[offNew + d] = pperm[plex->cones[off + d]]; plexNew->coneOrientations[offNew + d] = plex->coneOrientations[off + d]; } } PetscCall(PetscSectionDestroy(&plexNew->supportSection)); PetscCall(PetscSectionPermute(plex->supportSection, perm, &plexNew->supportSection)); PetscCall(PetscSectionGetStorageSize(plexNew->supportSection, &n)); PetscCall(PetscMalloc1(n, &plexNew->supports)); PetscCall(PetscSectionGetChart(plex->supportSection, &pStart, &pEnd)); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; PetscCall(PetscSectionGetDof(plexNew->supportSection, pperm[p], &dof)); PetscCall(PetscSectionGetOffset(plex->supportSection, p, &off)); PetscCall(PetscSectionGetOffset(plexNew->supportSection, pperm[p], &offNew)); for (d = 0; d < dof; ++d) plexNew->supports[offNew + d] = pperm[plex->supports[off + d]]; } PetscCall(ISRestoreIndices(perm, &pperm)); } /* Remap coordinates */ { DM cdm, cdmNew; PetscSection cs, csNew; Vec coordinates, coordinatesNew; PetscCall(DMGetCoordinateSection(dm, &cs)); PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); PetscCall(DMPlexRemapCoordinates_Private(perm, cs, coordinates, &csNew, &coordinatesNew)); PetscCall(DMSetCoordinateSection(*pdm, PETSC_DETERMINE, csNew)); PetscCall(DMSetCoordinatesLocal(*pdm, coordinatesNew)); PetscCall(PetscSectionDestroy(&csNew)); PetscCall(VecDestroy(&coordinatesNew)); PetscCall(DMGetCellCoordinateDM(dm, &cdm)); if (cdm) { PetscCall(DMGetCoordinateDM(*pdm, &cdm)); PetscCall(DMClone(cdm, &cdmNew)); PetscCall(DMSetCellCoordinateDM(*pdm, cdmNew)); PetscCall(DMDestroy(&cdmNew)); PetscCall(DMGetCellCoordinateSection(dm, &cs)); PetscCall(DMGetCellCoordinatesLocal(dm, &coordinates)); PetscCall(DMPlexRemapCoordinates_Private(perm, cs, coordinates, &csNew, &coordinatesNew)); PetscCall(DMSetCellCoordinateSection(*pdm, PETSC_DETERMINE, csNew)); PetscCall(DMSetCellCoordinatesLocal(*pdm, coordinatesNew)); PetscCall(PetscSectionDestroy(&csNew)); PetscCall(VecDestroy(&coordinatesNew)); } } PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *pdm)); (*pdm)->setupcalled = PETSC_TRUE; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMPlexReorderSetDefault_Plex(DM dm, DMReorderDefaultFlag reorder) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscFunctionBegin; mesh->reorderDefault = reorder; PetscFunctionReturn(PETSC_SUCCESS); } /*@ DMPlexReorderSetDefault - Set flag indicating whether the DM should be reordered by default Logically Collective Input Parameters: + dm - The `DM` - reorder - Flag for reordering Level: intermediate .seealso: `DMPlexReorderGetDefault()` @*/ PetscErrorCode DMPlexReorderSetDefault(DM dm, DMReorderDefaultFlag reorder) { PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscTryMethod(dm, "DMPlexReorderSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMPlexReorderGetDefault_Plex(DM dm, DMReorderDefaultFlag *reorder) { DM_Plex *mesh = (DM_Plex *)dm->data; PetscFunctionBegin; *reorder = mesh->reorderDefault; PetscFunctionReturn(PETSC_SUCCESS); } /*@ DMPlexReorderGetDefault - Get flag indicating whether the DM should be reordered by default Not Collective Input Parameter: . dm - The `DM` Output Parameter: . reorder - Flag for reordering Level: intermediate .seealso: `DMPlexReorderSetDefault()` @*/ PetscErrorCode DMPlexReorderGetDefault(DM dm, DMReorderDefaultFlag *reorder) { PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscAssertPointer(reorder, 2); PetscUseMethod(dm, "DMPlexReorderGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); PetscFunctionReturn(PETSC_SUCCESS); } static PetscErrorCode DMCreateSectionPermutation_Plex_Reverse(DM dm, IS *permutation, PetscBT *blockStarts) { IS permIS; PetscInt *perm; PetscInt pStart, pEnd; PetscFunctionBegin; PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(PetscMalloc1(pEnd - pStart, &perm)); for (PetscInt p = pStart; p < pEnd; ++p) perm[pEnd - 1 - p] = p; PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS)); PetscCall(ISSetPermutation(permIS)); *permutation = permIS; PetscFunctionReturn(PETSC_SUCCESS); } // Reorder to group split nodes static PetscErrorCode DMCreateSectionPermutation_Plex_Cohesive_Old(DM dm, IS *permutation, PetscBT *blockStarts) { IS permIS; PetscBT bt, blst; PetscInt *perm; PetscInt pStart, pEnd, i = 0; PetscFunctionBegin; PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(PetscMalloc1(pEnd - pStart, &perm)); PetscCall(PetscBTCreate(pEnd - pStart, &bt)); PetscCall(PetscBTCreate(pEnd - pStart, &blst)); for (PetscInt p = pStart; p < pEnd; ++p) { const PetscInt *supp, *cone; PetscInt suppSize; DMPolytopeType ct; PetscCall(DMPlexGetCellType(dm, p, &ct)); // Do not order tensor cells until they appear below if (ct == DM_POLYTOPE_POINT_PRISM_TENSOR || ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) continue; if (PetscBTLookupSet(bt, p)) continue; PetscCall(PetscBTSet(blst, p)); perm[i++] = p; // Check for tensor cells in the support PetscCall(DMPlexGetSupport(dm, p, &supp)); PetscCall(DMPlexGetSupportSize(dm, p, &suppSize)); for (PetscInt s = 0; s < suppSize; ++s) { DMPolytopeType sct; PetscInt q, qq; PetscCall(DMPlexGetCellType(dm, supp[s], &sct)); switch (sct) { case DM_POLYTOPE_POINT_PRISM_TENSOR: case DM_POLYTOPE_SEG_PRISM_TENSOR: case DM_POLYTOPE_TRI_PRISM_TENSOR: case DM_POLYTOPE_QUAD_PRISM_TENSOR: // If found, move up the split partner of the tensor cell, and the cell itself PetscCall(DMPlexGetCone(dm, supp[s], &cone)); qq = supp[s]; q = (cone[0] == p) ? cone[1] : cone[0]; if (!PetscBTLookupSet(bt, q)) { perm[i++] = q; s = suppSize; // At T-junctions, we can have an unsplit point at the other end, so also order that loop { const PetscInt *qsupp, *qcone; PetscInt qsuppSize; PetscCall(DMPlexGetSupport(dm, q, &qsupp)); PetscCall(DMPlexGetSupportSize(dm, q, &qsuppSize)); for (PetscInt qs = 0; qs < qsuppSize; ++qs) { DMPolytopeType qsct; PetscCall(DMPlexGetCellType(dm, qsupp[qs], &qsct)); switch (qsct) { case DM_POLYTOPE_POINT_PRISM_TENSOR: case DM_POLYTOPE_SEG_PRISM_TENSOR: case DM_POLYTOPE_TRI_PRISM_TENSOR: case DM_POLYTOPE_QUAD_PRISM_TENSOR: PetscCall(DMPlexGetCone(dm, qsupp[qs], &qcone)); if (qcone[0] == qcone[1]) { if (!PetscBTLookupSet(bt, qsupp[qs])) { perm[i++] = qsupp[qs]; qs = qsuppSize; } } break; default: break; } } } } if (!PetscBTLookupSet(bt, qq)) { perm[i++] = qq; s = suppSize; } break; default: break; } } } if (PetscDefined(USE_DEBUG)) { for (PetscInt p = pStart; p < pEnd; ++p) PetscCheck(PetscBTLookup(bt, p), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Index %" PetscInt_FMT " missed in permutation of [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); } PetscCall(PetscBTDestroy(&bt)); PetscCheck(i == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of points in permutation %" PetscInt_FMT " does not match chart size %" PetscInt_FMT, i, pEnd - pStart); PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS)); PetscCall(ISSetPermutation(permIS)); *permutation = permIS; *blockStarts = blst; PetscFunctionReturn(PETSC_SUCCESS); } // Mark the block associated with a cohesive cell p static PetscErrorCode InsertCohesiveBlock_Private(DM dm, PetscBT bt, PetscBT blst, PetscInt p, PetscInt *idx, PetscInt perm[]) { const PetscInt *cone; PetscInt cS; PetscFunctionBegin; if (PetscBTLookupSet(bt, p)) PetscFunctionReturn(PETSC_SUCCESS); // Order the endcaps PetscCall(DMPlexGetCone(dm, p, &cone)); PetscCall(DMPlexGetConeSize(dm, p, &cS)); if (blst) PetscCall(PetscBTSet(blst, cone[0])); if (!PetscBTLookupSet(bt, cone[0])) perm[(*idx)++] = cone[0]; if (!PetscBTLookupSet(bt, cone[1])) perm[(*idx)++] = cone[1]; // Order sides for (PetscInt c = 2; c < cS; ++c) PetscCall(InsertCohesiveBlock_Private(dm, bt, NULL, cone[c], idx, perm)); // Order cell perm[(*idx)++] = p; PetscFunctionReturn(PETSC_SUCCESS); } // Reorder to group split nodes static PetscErrorCode DMCreateSectionPermutation_Plex_Cohesive(DM dm, IS *permutation, PetscBT *blockStarts) { IS permIS; PetscBT bt, blst; PetscInt *perm; PetscInt dim, pStart, pEnd, i = 0; PetscFunctionBegin; PetscCall(DMGetDimension(dm, &dim)); PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); PetscCall(PetscMalloc1(pEnd - pStart, &perm)); PetscCall(PetscBTCreate(pEnd - pStart, &bt)); PetscCall(PetscBTCreate(pEnd - pStart, &blst)); // Add cohesive blocks for (PetscInt p = pStart; p < pEnd; ++p) { DMPolytopeType ct; PetscCall(DMPlexGetCellType(dm, p, &ct)); switch (dim) { case 2: if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) PetscCall(InsertCohesiveBlock_Private(dm, bt, blst, p, &i, perm)); break; case 3: if (ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) PetscCall(InsertCohesiveBlock_Private(dm, bt, blst, p, &i, perm)); break; default: break; } } // Add normal blocks for (PetscInt p = pStart; p < pEnd; ++p) { if (PetscBTLookupSet(bt, p)) continue; PetscCall(PetscBTSet(blst, p)); perm[i++] = p; } if (PetscDefined(USE_DEBUG)) { for (PetscInt p = pStart; p < pEnd; ++p) PetscCheck(PetscBTLookup(bt, p), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Index %" PetscInt_FMT " missed in permutation of [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); } PetscCall(PetscBTDestroy(&bt)); PetscCheck(i == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of points in permutation %" PetscInt_FMT " does not match chart size %" PetscInt_FMT, i, pEnd - pStart); PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS)); PetscCall(ISSetPermutation(permIS)); *permutation = permIS; *blockStarts = blst; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMCreateSectionPermutation_Plex(DM dm, IS *perm, PetscBT *blockStarts) { DMReorderDefaultFlag reorder; MatOrderingType otype; PetscBool iscohesive, iscohesiveOld, isreverse; PetscFunctionBegin; PetscCall(DMReorderSectionGetDefault(dm, &reorder)); if (reorder != DM_REORDER_DEFAULT_TRUE) PetscFunctionReturn(PETSC_SUCCESS); PetscCall(DMReorderSectionGetType(dm, &otype)); if (!otype) PetscFunctionReturn(PETSC_SUCCESS); PetscCall(PetscStrncmp(otype, "cohesive_old", 1024, &iscohesiveOld)); PetscCall(PetscStrncmp(otype, "cohesive", 1024, &iscohesive)); PetscCall(PetscStrncmp(otype, "reverse", 1024, &isreverse)); if (iscohesive) PetscCall(DMCreateSectionPermutation_Plex_Cohesive(dm, perm, blockStarts)); else if (iscohesiveOld) PetscCall(DMCreateSectionPermutation_Plex_Cohesive_Old(dm, perm, blockStarts)); else if (isreverse) PetscCall(DMCreateSectionPermutation_Plex_Reverse(dm, perm, blockStarts)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMReorderSectionSetDefault_Plex(DM dm, DMReorderDefaultFlag reorder) { PetscFunctionBegin; dm->reorderSection = reorder; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMReorderSectionGetDefault_Plex(DM dm, DMReorderDefaultFlag *reorder) { PetscFunctionBegin; *reorder = dm->reorderSection; PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMReorderSectionSetType_Plex(DM dm, MatOrderingType reorder) { PetscFunctionBegin; PetscCall(PetscFree(dm->reorderSectionType)); PetscCall(PetscStrallocpy(reorder, (char **)&dm->reorderSectionType)); PetscFunctionReturn(PETSC_SUCCESS); } PetscErrorCode DMReorderSectionGetType_Plex(DM dm, MatOrderingType *reorder) { PetscFunctionBegin; *reorder = dm->reorderSectionType; PetscFunctionReturn(PETSC_SUCCESS); }