Hello PETSc team,

I am trying to extrude some cells from a mesh that comes from a DMForest. The DMForest is converted to a DMPlex which is then being used in a modified version of DMPlexExtrude (patch is included). The issue is the DMForest to DMPlex conversion switches the stratum ordering. It appears that DMPlexTransform assumes that you have the standard DMPlex ordering: Cells->Vertices->Edges in 2D. The plex that comes from DMForest has Cells->Edges->Vertices. This results in an edge being incorrectly flagged as outside of the range of edges.

I'm including a minimal code showing this. Sample output and the error message is also shown below.

Thanks,

Dave


Original Plex:
    0: [100,221)
    1: [221,441)
    2: [0,100)
Before Extrude Box: +0.000000e+00, +1.000000e+00 +0.000000e+00, +1.000000e+00  After Extrude Box: -1.000000e-01, +1.100000e+00 -1.000000e-01, +1.100000e+00


Converted Plex:
    0: [320,441)
    1: [100,320)
    2: [0,100)
Before Extrude Box: +0.000000e+00, +1.000000e+00 +0.000000e+00, +1.000000e+00 [0]PETSC ERROR: --------------------- Error Message --------------------------------------------------------------
[0]PETSC ERROR: PETSc has generated inconsistent data
[0]PETSC ERROR: Point 100 is not a segment [221, 441)
[0]PETSC ERROR: See 
https://urldefense.us/v3/__https://petsc.org/release/faq/__;!!G_uCfscf7eWS!cKv8WrCLXVqU9jE_pHlDNyVtTMk8aT2xxJcPTjksuQP4PiWtA5Kv8E0Ph8jKhOm7MbkM6qFHmK3R5N4y_sQ$
  for trouble shooting.
[0]PETSC ERROR: PETSc Development Git Revision: v3.23.3-199-g3b15527e756 Git Date: 2025-06-03 15:20:49 +0000 [0]PETSC ERROR: ./ex with 1 MPI process(es) and PETSC_ARCH arch-ablate-opt on libuse.eng.buffalo.edu by davidsal Wed Jun  4 10:39:41 2025 [0]PETSC ERROR: Configure options: --with-64-bit-indices=0 --download-metis --download-mpich --download-p4est --download-parmetis --download-scalapack --download-slepc --download-tetgen --download-triangle --download-zlib --with-debugging=0 --with-libpng --with-slepc PETSC_ARCH=arch-ablate-opt --with-fortran-bindings=0 [0]PETSC ERROR: #1 DMPlexTransformGetTargetPoint() at /home/davidsal/Research/petsc/src/dm/impls/plex/transform/interface/plextransform.c:1003 [0]PETSC ERROR: #2 DMPlexTransformSetConeSizes() at /home/davidsal/Research/petsc/src/dm/impls/plex/transform/interface/plextransform.c:1400 [0]PETSC ERROR: #3 DMPlexTransformApply() at /home/davidsal/Research/petsc/src/dm/impls/plex/transform/interface/plextransform.c:2385 [0]PETSC ERROR: #4 DMPlexExtrude() at /home/davidsal/Research/petsc/src/dm/impls/plex/plexextrude.c:82
[0]PETSC ERROR: #5 extrudeMesh() at ex.c:34
[0]PETSC ERROR: #6 main() at ex.c:86
[0]PETSC ERROR: No PETSc Option Table entries
[0]PETSC ERROR: ----------------End of Error Message -------send entire error message to petsc-ma...@mcs.anl.gov----------

diff --git a/include/petscdmplex.h b/include/petscdmplex.h
index 6b52d8b..8ba1f7d 100644
--- a/include/petscdmplex.h
+++ b/include/petscdmplex.h
@@ -187,7 +187,7 @@ PETSC_EXTERN PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm, DMPlexTPSType, const P
 PETSC_EXTERN PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm, PetscInt, PetscBool, DM *);
 PETSC_EXTERN PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm, const PetscInt[], const PetscReal[], const PetscReal[], const DMBoundaryType[], PetscBool, PetscBool, DM *);
 PETSC_EXTERN PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm, PetscInt, const PetscInt[], const PetscReal[], const PetscReal[], PetscInt, DM *);
-PETSC_EXTERN PetscErrorCode DMPlexExtrude(DM, PetscInt, PetscReal, PetscBool, PetscBool, PetscBool, const PetscReal[], const PetscReal[], DM *);
+PETSC_EXTERN PetscErrorCode DMPlexExtrude(DM, PetscInt, PetscReal, PetscBool, PetscBool, PetscBool, const PetscReal[], const PetscReal[], DMLabel, DM *);
 
 PETSC_EXTERN PetscErrorCode DMPlexSetIsoperiodicFaceSF(DM, PetscInt, PetscSF *);
 PETSC_EXTERN PetscErrorCode DMPlexGetIsoperiodicFaceSF(DM, PetscInt *, const PetscSF **);
diff --git a/src/dm/impls/plex/plexcreate.c b/src/dm/impls/plex/plexcreate.c
index 40352d7..a289c25 100644
--- a/src/dm/impls/plex/plexcreate.c
+++ b/src/dm/impls/plex/plexcreate.c
@@ -2051,7 +2051,7 @@ static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt fa
   PetscCall(DMSetDimension(bdm, 2));
   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
-  PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, &vol));
+  PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, NULL, &vol));
   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
   PetscCall(DMDestroy(&bdm));
   PetscCall(DMPlexReplace_Internal(dm, &vol));
diff --git a/src/dm/impls/plex/plexextrude.c b/src/dm/impls/plex/plexextrude.c
index b8c3fbb..8c2add4 100644
--- a/src/dm/impls/plex/plexextrude.c
+++ b/src/dm/impls/plex/plexextrude.c
@@ -48,7 +48,7 @@
 
 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMExtrude()`, `DMPlexTransform`, `DMPlexTransformExtrudeSetThickness()`, `DMPlexTransformExtrudeSetTensor()`
 @*/
-PetscErrorCode DMPlexExtrude(DM dm, PetscInt layers, PetscReal thickness, PetscBool tensor, PetscBool symmetric, PetscBool periodic, const PetscReal normal[], const PetscReal thicknesses[], DM *edm)
+PetscErrorCode DMPlexExtrude(DM dm, PetscInt layers, PetscReal thickness, PetscBool tensor, PetscBool symmetric, PetscBool periodic, const PetscReal normal[], const PetscReal thicknesses[], DMLabel adaptLabel, DM *edm)
 {
   DMPlexTransform tr;
   DM              cdm;
@@ -74,6 +74,7 @@ PetscErrorCode DMPlexExtrude(DM dm, PetscInt layers, PetscReal thickness, PetscB
   PetscCall(DMPlexTransformExtrudeSetPeriodic(tr, periodic));
   if (normal) PetscCall(DMPlexTransformExtrudeSetNormal(tr, normal));
   if (thicknesses) PetscCall(DMPlexTransformExtrudeSetThicknesses(tr, layers, thicknesses));
+  if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel));
   PetscCall(DMPlexTransformSetFromOptions(tr));
   PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
   PetscCall(DMPlexTransformSetUp(tr));
@@ -130,7 +131,7 @@ PetscErrorCode DMPlexExtrude(DM dm, PetscInt layers, PetscReal thickness, PetscB
 PetscErrorCode DMExtrude_Plex(DM dm, PetscInt layers, DM *edm)
 {
   PetscFunctionBegin;
-  PetscCall(DMPlexExtrude(dm, layers, PETSC_DETERMINE, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, edm));
+  PetscCall(DMPlexExtrude(dm, layers, PETSC_DETERMINE, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, NULL, edm));
   PetscCall(DMSetMatType(*edm, dm->mattype));
   PetscCall(DMViewFromOptions(*edm, NULL, "-check_extrude"));
   PetscFunctionReturn(PETSC_SUCCESS);
#include <petscdmplex.h>
#include <petscdmforest.h>
#include <petscdmplextransform.h>

PetscErrorCode extrudeMesh(DM dm, DM *dmExtrude) {
  DMLabel   extrudeLabel;
  PetscInt  fStart, fEnd, vStart, vEnd;
  PetscInt  nLayers = 2;
  PetscReal thickness = 0.1;

  PetscFunctionBegin;
  PetscCall(DMLabelCreate(PETSC_COMM_SELF, "extrudeLabel", &extrudeLabel));
  PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); // Faces
  PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));  // Vertices

  for (PetscInt f = fStart; f < fEnd; ++f) {
    PetscInt        suppSize, numPoints;
    PetscInt       *points = NULL;

    // Only use faces attached to one cell
    PetscCall(DMPlexGetSupportSize(dm, f, &suppSize));
    if (suppSize > 1) continue;

    // Get everything at a lower dimension than the face
    PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &numPoints, &points));
    for (PetscInt cl = 0; cl < numPoints * 2; cl += 2) {
      const PetscInt v = points[cl];
      if ((v >= vStart) && (v < vEnd)) {
        PetscCall(DMLabelSetValue(extrudeLabel, v, DM_ADAPT_REFINE));
      }
    }
    PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &numPoints, &points));
  }
  PetscCall(DMPlexExtrude(dm, nLayers, thickness, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, extrudeLabel, dmExtrude));
  PetscCall(DMLabelDestroy(&extrudeLabel));
  PetscFunctionReturn(PETSC_SUCCESS);
}



int main(int argc,char **argv)
{
  PetscCall(PetscInitialize(&argc, &argv, NULL, NULL));

  DM             dmPlex, dmForest, dmExtrude;
  PetscInt       dim = 2;
  PetscInt       pStart, pEnd;
  PetscInt       faces[2] = {10, 10};
  PetscReal      lower[2] = {0, 0}, upper[2] = {1, 1};
  PetscBool      interpolate = PETSC_TRUE;
  DMBoundaryType periodicity[2] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};

  // Base plex
  PetscCall(DMPlexCreateBoxMesh(PETSC_COMM_WORLD, dim, PETSC_FALSE, faces, lower, upper, periodicity, interpolate, dim, PETSC_TRUE, &dmPlex));

  PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Original Plex:\n"));
  for (PetscInt d = 0; d <= dim; ++d) {
    PetscCall(DMPlexGetDepthStratum(dmPlex, d, &pStart, &pEnd));
    PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\t%d: [%d,%d)\n", d, pStart, pEnd));
  }
  PetscCall(DMGetBoundingBox(dmPlex, lower, upper));
  PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Before Extrude Box: %+e, %+e\t%+e, %+e\n", lower[0], upper[0], lower[1], upper[1]));
  PetscCall(extrudeMesh(dmPlex, &dmExtrude));
  PetscCall(DMGetBoundingBox(dmExtrude, lower, upper));
  PetscCall(PetscPrintf(PETSC_COMM_WORLD, " After Extrude Box: %+e, %+e\t%+e, %+e\n", lower[0], upper[0], lower[1], upper[1]));
  PetscCall(DMDestroy(&dmExtrude));

  PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n\n"));

  // forest
  PetscCall(DMCreate(PETSC_COMM_WORLD, &dmForest));
  PetscCall(DMSetType(dmForest, DMP4EST));
  PetscCall(DMForestSetBaseDM(dmForest, dmPlex));
  PetscCall(DMSetUp(dmForest));
  PetscCall(DMDestroy(&dmPlex));
  PetscCall(DMConvert(dmForest, DMPLEX, &dmPlex));
  PetscCall(DMDestroy(&dmForest));

  PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Converted Plex:\n"));
  for (PetscInt d = 0; d <= dim; ++d) {
    PetscCall(DMPlexGetDepthStratum(dmPlex, d, &pStart, &pEnd));
    PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\t%d: [%d,%d)\n", d, pStart, pEnd));
  }
  PetscCall(DMGetBoundingBox(dmPlex, lower, upper));
  PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Before Extrude Box: %+e, %+e\t%+e, %+e\n", lower[0], upper[0], lower[1], upper[1]));
  PetscCall(extrudeMesh(dmPlex, &dmExtrude));
  PetscCall(DMGetBoundingBox(dmExtrude, lower, upper));
  PetscCall(PetscPrintf(PETSC_COMM_WORLD, " After Extrude Box: %+e, %+e\t%+e, %+e\n", lower[0], upper[0], lower[1], upper[1]));

  PetscCall(DMDestroy(&dmExtrude));
  PetscCall(DMDestroy(&dmPlex));


  PetscCall(PetscFinalize());
  return PETSC_SUCCESS;
}

Reply via email to