xref: /petsc/src/dm/impls/plex/plexsfc.c (revision c77877e3265679d5c0d1c32598d8281d7fd127dd)
13e72e933SJed Brown #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
23e72e933SJed Brown #include <petscsf.h>
33e72e933SJed Brown #include <petsc/private/hashset.h>
43e72e933SJed Brown 
53e72e933SJed Brown typedef uint64_t ZCode;
63e72e933SJed Brown 
73e72e933SJed Brown PETSC_HASH_SET(ZSet, ZCode, PetscHash_UInt64, PetscHashEqual)
83e72e933SJed Brown 
93e72e933SJed Brown typedef struct {
103e72e933SJed Brown   PetscInt i, j, k;
113e72e933SJed Brown } Ijk;
123e72e933SJed Brown 
133e72e933SJed Brown typedef struct {
143e72e933SJed Brown   Ijk         eextent;
153e72e933SJed Brown   Ijk         vextent;
163e72e933SJed Brown   PetscMPIInt comm_size;
173e72e933SJed Brown   ZCode      *zstarts;
183e72e933SJed Brown } ZLayout;
193e72e933SJed Brown 
203e72e933SJed Brown static unsigned ZCodeSplit1(ZCode z)
213e72e933SJed Brown {
223e72e933SJed Brown   z = ((z & 01001001001001001) | ((z >> 2) & 02002002002002002) | ((z >> 4) & 04004004004004004));
233e72e933SJed Brown   z = (z | (z >> 6) | (z >> 12)) & 0000000777000000777;
243e72e933SJed Brown   z = (z | (z >> 18)) & 0777777;
253e72e933SJed Brown   return (unsigned)z;
263e72e933SJed Brown }
273e72e933SJed Brown 
283e72e933SJed Brown static ZCode ZEncode1(unsigned t)
293e72e933SJed Brown {
303e72e933SJed Brown   ZCode z = t;
313e72e933SJed Brown   z       = (z | (z << 18)) & 0777000000777;
323e72e933SJed Brown   z       = (z | (z << 6) | (z << 12)) & 07007007007007007;
333e72e933SJed Brown   z       = (z | (z << 2) | (z << 4)) & 0111111111111111111;
343e72e933SJed Brown   return z;
353e72e933SJed Brown }
363e72e933SJed Brown 
373e72e933SJed Brown static Ijk ZCodeSplit(ZCode z)
383e72e933SJed Brown {
393e72e933SJed Brown   Ijk c;
403e72e933SJed Brown   c.i = ZCodeSplit1(z >> 2);
413e72e933SJed Brown   c.j = ZCodeSplit1(z >> 1);
423e72e933SJed Brown   c.k = ZCodeSplit1(z >> 0);
433e72e933SJed Brown   return c;
443e72e933SJed Brown }
453e72e933SJed Brown 
463e72e933SJed Brown static ZCode ZEncode(Ijk c)
473e72e933SJed Brown {
483e72e933SJed Brown   ZCode z = (ZEncode1(c.i) << 2) | (ZEncode1(c.j) << 1) | ZEncode1(c.k);
493e72e933SJed Brown   return z;
503e72e933SJed Brown }
513e72e933SJed Brown 
523e72e933SJed Brown static PetscBool IjkActive(Ijk extent, Ijk l)
533e72e933SJed Brown {
543e72e933SJed Brown   if (l.i < extent.i && l.j < extent.j && l.k < extent.k) return PETSC_TRUE;
553e72e933SJed Brown   return PETSC_FALSE;
563e72e933SJed Brown }
573e72e933SJed Brown 
583e72e933SJed Brown // Since element/vertex box extents are typically not equal powers of 2, Z codes that lie within the domain are not contiguous.
59*c77877e3SJed Brown static PetscErrorCode ZLayoutCreate(PetscMPIInt size, const PetscInt eextent[3], const PetscInt vextent[3], ZLayout *zlayout)
603e72e933SJed Brown {
613e72e933SJed Brown   ZLayout layout;
62*c77877e3SJed Brown 
63*c77877e3SJed Brown   PetscFunctionBegin;
643e72e933SJed Brown   layout.eextent.i = eextent[0];
653e72e933SJed Brown   layout.eextent.j = eextent[1];
663e72e933SJed Brown   layout.eextent.k = eextent[2];
673e72e933SJed Brown   layout.vextent.i = vextent[0];
683e72e933SJed Brown   layout.vextent.j = vextent[1];
693e72e933SJed Brown   layout.vextent.k = vextent[2];
703e72e933SJed Brown   layout.comm_size = size;
71*c77877e3SJed Brown   PetscCall(PetscMalloc1(size + 1, &layout.zstarts));
723e72e933SJed Brown 
733e72e933SJed Brown   PetscInt total_elems = eextent[0] * eextent[1] * eextent[2];
743e72e933SJed Brown   ZCode    z           = 0;
753e72e933SJed Brown   layout.zstarts[0]    = 0;
763e72e933SJed Brown   for (PetscMPIInt r = 0; r < size; r++) {
773e72e933SJed Brown     PetscInt elems_needed = (total_elems / size) + (total_elems % size > r), count;
783e72e933SJed Brown     for (count = 0; count < elems_needed; z++) {
793e72e933SJed Brown       Ijk loc = ZCodeSplit(z);
803e72e933SJed Brown       if (IjkActive(layout.eextent, loc)) count++;
813e72e933SJed Brown     }
823e72e933SJed Brown     // Pick up any extra vertices in the Z ordering before the next rank's first owned element.
83*c77877e3SJed Brown     //
84*c77877e3SJed Brown     // TODO: This leads to poorly balanced vertices when eextent is a power of 2, since all the fringe vertices end up
85*c77877e3SJed Brown     // on the last rank. A possible solution is to balance the Z-order vertices independently from the cells, which will
86*c77877e3SJed Brown     // result in a lot of element closures being remote. We could finish marking boundary conditions, then do a round of
87*c77877e3SJed Brown     // vertex ownership smoothing (which would reorder and redistribute vertices without touching element distribution).
88*c77877e3SJed Brown     // Another would be to have an analytic ownership criteria for vertices in the fringe veextent - eextent. This would
89*c77877e3SJed Brown     // complicate the job of identifying an owner and its offset.
903e72e933SJed Brown     for (; z <= ZEncode(layout.vextent); z++) {
913e72e933SJed Brown       Ijk loc = ZCodeSplit(z);
923e72e933SJed Brown       if (IjkActive(layout.eextent, loc)) break;
933e72e933SJed Brown     }
943e72e933SJed Brown     layout.zstarts[r + 1] = z;
953e72e933SJed Brown   }
96*c77877e3SJed Brown   *zlayout = layout;
97*c77877e3SJed Brown   PetscFunctionReturn(0);
983e72e933SJed Brown }
993e72e933SJed Brown 
1003e72e933SJed Brown PetscInt ZCodeFind(ZCode key, PetscInt n, const ZCode X[])
1013e72e933SJed Brown {
1023e72e933SJed Brown   PetscInt lo = 0, hi = n;
1033e72e933SJed Brown 
1043e72e933SJed Brown   if (n == 0) return -1;
1053e72e933SJed Brown   while (hi - lo > 1) {
1063e72e933SJed Brown     PetscInt mid = lo + (hi - lo) / 2;
1073e72e933SJed Brown     if (key < X[mid]) hi = mid;
1083e72e933SJed Brown     else lo = mid;
1093e72e933SJed Brown   }
1103e72e933SJed Brown   return key == X[lo] ? lo : -(lo + (key > X[lo]) + 1);
1113e72e933SJed Brown }
1123e72e933SJed Brown 
1133e72e933SJed Brown PetscErrorCode DMPlexCreateBoxMesh_Tensor_SFC_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1143e72e933SJed Brown {
1153e72e933SJed Brown   PetscInt  eextent[3] = {1, 1, 1}, vextent[3] = {1, 1, 1};
1163e72e933SJed Brown   const Ijk closure_1[] = {
1173e72e933SJed Brown     {0, 0, 0},
1183e72e933SJed Brown     {1, 0, 0},
1193e72e933SJed Brown   };
1203e72e933SJed Brown   const Ijk closure_2[] = {
1213e72e933SJed Brown     {0, 0, 0},
1223e72e933SJed Brown     {1, 0, 0},
1233e72e933SJed Brown     {1, 1, 0},
1243e72e933SJed Brown     {0, 1, 0},
1253e72e933SJed Brown   };
1263e72e933SJed Brown   const Ijk closure_3[] = {
1273e72e933SJed Brown     {0, 0, 0},
1283e72e933SJed Brown     {0, 1, 0},
1293e72e933SJed Brown     {1, 1, 0},
1303e72e933SJed Brown     {1, 0, 0},
1313e72e933SJed Brown     {0, 0, 1},
1323e72e933SJed Brown     {1, 0, 1},
1333e72e933SJed Brown     {1, 1, 1},
1343e72e933SJed Brown     {0, 1, 1},
1353e72e933SJed Brown   };
1363431e603SJed Brown   const Ijk *const closure_dim[] = {NULL, closure_1, closure_2, closure_3};
1373431e603SJed Brown   // This must be kept consistent with DMPlexCreateCubeMesh_Internal
1383431e603SJed Brown   const PetscInt        face_marker_1[]   = {1, 2};
1393431e603SJed Brown   const PetscInt        face_marker_2[]   = {4, 2, 1, 3};
1403431e603SJed Brown   const PetscInt        face_marker_3[]   = {6, 5, 3, 4, 1, 2};
1413431e603SJed Brown   const PetscInt *const face_marker_dim[] = {NULL, face_marker_1, face_marker_2, face_marker_3};
1423e72e933SJed Brown 
1433e72e933SJed Brown   PetscFunctionBegin;
1443e72e933SJed Brown   PetscValidPointer(dm, 1);
1453e72e933SJed Brown   PetscValidLogicalCollectiveInt(dm, dim, 2);
1463e72e933SJed Brown   PetscCall(DMSetDimension(dm, dim));
1473e72e933SJed Brown   PetscMPIInt rank, size;
1483e72e933SJed Brown   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1493e72e933SJed Brown   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1503e72e933SJed Brown   for (PetscInt i = 0; i < dim; i++) {
1513e72e933SJed Brown     eextent[i] = faces[i];
1523e72e933SJed Brown     vextent[i] = faces[i] + 1;
1533e72e933SJed Brown   }
154*c77877e3SJed Brown   ZLayout layout;
155*c77877e3SJed Brown   PetscCall(ZLayoutCreate(size, eextent, vextent, &layout));
1563e72e933SJed Brown   PetscZSet vset; // set of all vertices in the closure of the owned elements
1573e72e933SJed Brown   PetscCall(PetscZSetCreate(&vset));
1583e72e933SJed Brown   PetscInt local_elems = 0;
1593e72e933SJed Brown   for (ZCode z = layout.zstarts[rank]; z < layout.zstarts[rank + 1]; z++) {
1603e72e933SJed Brown     Ijk loc = ZCodeSplit(z);
1613e72e933SJed Brown     if (IjkActive(layout.vextent, loc)) PetscZSetAdd(vset, z);
1623e72e933SJed Brown     if (IjkActive(layout.eextent, loc)) {
1633e72e933SJed Brown       local_elems++;
1643e72e933SJed Brown       // Add all neighboring vertices to set
1653e72e933SJed Brown       for (PetscInt n = 0; n < PetscPowInt(2, dim); n++) {
1663e72e933SJed Brown         Ijk   inc  = closure_dim[dim][n];
1673e72e933SJed Brown         Ijk   nloc = {loc.i + inc.i, loc.j + inc.j, loc.k + inc.k};
1683e72e933SJed Brown         ZCode v    = ZEncode(nloc);
1693e72e933SJed Brown         PetscZSetAdd(vset, v);
1703e72e933SJed Brown       }
1713e72e933SJed Brown     }
1723e72e933SJed Brown   }
1733e72e933SJed Brown   PetscInt local_verts, off = 0;
1743e72e933SJed Brown   ZCode   *vert_z;
1753e72e933SJed Brown   PetscCall(PetscZSetGetSize(vset, &local_verts));
1763e72e933SJed Brown   PetscCall(PetscMalloc1(local_verts, &vert_z));
1773e72e933SJed Brown   PetscCall(PetscZSetGetElems(vset, &off, vert_z));
1783e72e933SJed Brown   PetscCall(PetscZSetDestroy(&vset));
1793e72e933SJed Brown   // ZCode is unsigned for bitwise convenience, but highest bit should never be set, so can interpret as signed
1803e72e933SJed Brown   PetscCall(PetscSortInt64(local_verts, (PetscInt64 *)vert_z));
1813e72e933SJed Brown 
1823e72e933SJed Brown   PetscCall(DMPlexSetChart(dm, 0, local_elems + local_verts));
1833e72e933SJed Brown   for (PetscInt e = 0; e < local_elems; e++) PetscCall(DMPlexSetConeSize(dm, e, PetscPowInt(2, dim)));
1843e72e933SJed Brown   PetscCall(DMSetUp(dm));
1853e72e933SJed Brown   {
1863e72e933SJed Brown     PetscInt e = 0;
1873e72e933SJed Brown     for (ZCode z = layout.zstarts[rank]; z < layout.zstarts[rank + 1]; z++) {
1883e72e933SJed Brown       Ijk loc = ZCodeSplit(z);
1893e72e933SJed Brown       if (!IjkActive(layout.eextent, loc)) continue;
1903e72e933SJed Brown       PetscInt cone[8], orient[8] = {0};
1913e72e933SJed Brown       for (PetscInt n = 0; n < PetscPowInt(2, dim); n++) {
1923e72e933SJed Brown         Ijk      inc  = closure_dim[dim][n];
1933e72e933SJed Brown         Ijk      nloc = {loc.i + inc.i, loc.j + inc.j, loc.k + inc.k};
1943e72e933SJed Brown         ZCode    v    = ZEncode(nloc);
1953e72e933SJed Brown         PetscInt ci   = ZCodeFind(v, local_verts, vert_z);
1963e72e933SJed Brown         PetscAssert(ci >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not find neighbor vertex in set");
1973e72e933SJed Brown         cone[n] = local_elems + ci;
1983e72e933SJed Brown       }
1993e72e933SJed Brown       PetscCall(DMPlexSetCone(dm, e, cone));
2003e72e933SJed Brown       PetscCall(DMPlexSetConeOrientation(dm, e, orient));
2013e72e933SJed Brown       e++;
2023e72e933SJed Brown     }
2033e72e933SJed Brown   }
2043e72e933SJed Brown 
2053e72e933SJed Brown   if (0) {
2063e72e933SJed Brown     DMLabel depth;
2073e72e933SJed Brown     PetscCall(DMCreateLabel(dm, "depth"));
2083e72e933SJed Brown     PetscCall(DMPlexGetDepthLabel(dm, &depth));
2093e72e933SJed Brown     PetscCall(DMLabelSetStratumBounds(depth, 0, local_elems, local_elems + local_verts));
2103e72e933SJed Brown     PetscCall(DMLabelSetStratumBounds(depth, 1, 0, local_elems));
2113e72e933SJed Brown   } else {
2123e72e933SJed Brown     PetscCall(DMPlexSymmetrize(dm));
2133e72e933SJed Brown     PetscCall(DMPlexStratify(dm));
2143e72e933SJed Brown   }
2153e72e933SJed Brown   { // Create point SF
2163e72e933SJed Brown     PetscSF sf;
2173e72e933SJed Brown     PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf);
2183e72e933SJed Brown     PetscInt owned_verts = ZCodeFind(layout.zstarts[rank + 1], local_verts, vert_z);
2193e72e933SJed Brown     if (owned_verts < 0) owned_verts = -(owned_verts + 1); // We don't care whether the key was found
2203e72e933SJed Brown     PetscInt     num_ghosts = local_verts - owned_verts;   // Due to sorting, owned vertices always come first
2213e72e933SJed Brown     PetscInt    *local_ghosts;
2223e72e933SJed Brown     PetscSFNode *ghosts;
2233e72e933SJed Brown     PetscCall(PetscMalloc1(num_ghosts, &local_ghosts));
2243e72e933SJed Brown     PetscCall(PetscMalloc1(num_ghosts, &ghosts));
2253e72e933SJed Brown     for (PetscInt i = 0; i < num_ghosts;) {
2263e72e933SJed Brown       ZCode    z           = vert_z[owned_verts + i];
2273e72e933SJed Brown       PetscInt remote_rank = ZCodeFind(z, size + 1, layout.zstarts), remote_count = 0;
2283e72e933SJed Brown       if (remote_rank < 0) remote_rank = -(remote_rank + 1) - 1;
2293e72e933SJed Brown       // We have a new remote rank; find all the ghost indices (which are contiguous in vert_z)
2303e72e933SJed Brown 
2313e72e933SJed Brown       // Count the elements on remote_rank
2323e72e933SJed Brown       PetscInt remote_elem = 0;
2333e72e933SJed Brown       for (ZCode rz = layout.zstarts[remote_rank]; rz < layout.zstarts[remote_rank + 1]; rz++) {
2343e72e933SJed Brown         Ijk loc = ZCodeSplit(rz);
2353e72e933SJed Brown         if (IjkActive(layout.eextent, loc)) remote_elem++;
2363e72e933SJed Brown       }
2373e72e933SJed Brown 
2383e72e933SJed Brown       // Traverse vertices and make ghost links
2393e72e933SJed Brown       for (ZCode rz = layout.zstarts[remote_rank]; rz < layout.zstarts[remote_rank + 1]; rz++) {
2403e72e933SJed Brown         Ijk loc = ZCodeSplit(rz);
2413e72e933SJed Brown         if (rz == z) {
2423e72e933SJed Brown           local_ghosts[i] = local_elems + owned_verts + i;
2433e72e933SJed Brown           ghosts[i].rank  = remote_rank;
2443e72e933SJed Brown           ghosts[i].index = remote_elem + remote_count;
2453e72e933SJed Brown           i++;
2463e72e933SJed Brown           if (i == num_ghosts) break;
2473e72e933SJed Brown           z = vert_z[owned_verts + i];
2483e72e933SJed Brown         }
2493e72e933SJed Brown         if (IjkActive(layout.vextent, loc)) remote_count++;
2503e72e933SJed Brown       }
2513e72e933SJed Brown     }
2523e72e933SJed Brown     PetscCall(PetscSFSetGraph(sf, local_elems + local_verts, num_ghosts, local_ghosts, PETSC_OWN_POINTER, ghosts, PETSC_OWN_POINTER));
2533e72e933SJed Brown     PetscCall(PetscObjectSetName((PetscObject)sf, "SFC Point SF"));
2543e72e933SJed Brown     PetscCall(DMSetPointSF(dm, sf));
2553e72e933SJed Brown     PetscCall(PetscSFDestroy(&sf));
2563e72e933SJed Brown   }
2573e72e933SJed Brown   {
2583e72e933SJed Brown     Vec          coordinates;
2593e72e933SJed Brown     PetscScalar *coords;
2603e72e933SJed Brown     PetscSection coord_section;
2613e72e933SJed Brown     PetscInt     coord_size;
2623e72e933SJed Brown     PetscCall(DMGetCoordinateSection(dm, &coord_section));
2633e72e933SJed Brown     PetscCall(PetscSectionSetNumFields(coord_section, 1));
2643e72e933SJed Brown     PetscCall(PetscSectionSetFieldComponents(coord_section, 0, dim));
2653e72e933SJed Brown     PetscCall(PetscSectionSetChart(coord_section, local_elems, local_elems + local_verts));
2663e72e933SJed Brown     for (PetscInt v = 0; v < local_verts; v++) {
2673e72e933SJed Brown       PetscInt point = local_elems + v;
2683e72e933SJed Brown       PetscCall(PetscSectionSetDof(coord_section, point, dim));
2693e72e933SJed Brown       PetscCall(PetscSectionSetFieldDof(coord_section, point, 0, dim));
2703e72e933SJed Brown     }
2713e72e933SJed Brown     PetscCall(PetscSectionSetUp(coord_section));
2723e72e933SJed Brown     PetscCall(PetscSectionGetStorageSize(coord_section, &coord_size));
2733e72e933SJed Brown     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2743e72e933SJed Brown     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2753e72e933SJed Brown     PetscCall(VecSetSizes(coordinates, coord_size, PETSC_DETERMINE));
2763e72e933SJed Brown     PetscCall(VecSetBlockSize(coordinates, dim));
2773e72e933SJed Brown     PetscCall(VecSetType(coordinates, VECSTANDARD));
2783e72e933SJed Brown     PetscCall(VecGetArray(coordinates, &coords));
2793e72e933SJed Brown     for (PetscInt v = 0; v < local_verts; v++) {
2803e72e933SJed Brown       Ijk loc             = ZCodeSplit(vert_z[v]);
2813e72e933SJed Brown       coords[v * dim + 0] = lower[0] + loc.i * (upper[0] - lower[0]) / layout.eextent.i;
2823e72e933SJed Brown       if (dim > 1) coords[v * dim + 1] = lower[1] + loc.j * (upper[1] - lower[1]) / layout.eextent.j;
2833e72e933SJed Brown       if (dim > 2) coords[v * dim + 2] = lower[2] + loc.k * (upper[2] - lower[2]) / layout.eextent.k;
2843e72e933SJed Brown     }
2853e72e933SJed Brown     PetscCall(VecRestoreArray(coordinates, &coords));
2863e72e933SJed Brown     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2873e72e933SJed Brown     PetscCall(VecDestroy(&coordinates));
2883e72e933SJed Brown     PetscCall(PetscFree(layout.zstarts));
2893e72e933SJed Brown   }
2903e72e933SJed Brown   if (interpolate) {
2913431e603SJed Brown     PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2923431e603SJed Brown 
2933431e603SJed Brown     DMLabel label;
2943431e603SJed Brown     PetscCall(DMCreateLabel(dm, "Face Sets"));
2953431e603SJed Brown     PetscCall(DMGetLabel(dm, "Face Sets", &label));
2963431e603SJed Brown     PetscInt fStart, fEnd, vStart, vEnd;
2973431e603SJed Brown     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2983431e603SJed Brown     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2993431e603SJed Brown     for (PetscInt f = fStart; f < fEnd; f++) {
3003431e603SJed Brown       PetscInt  npoints;
3013431e603SJed Brown       PetscInt *points = NULL;
3023431e603SJed Brown       PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &npoints, &points));
3033431e603SJed Brown       PetscInt bc_count[6] = {0};
3043431e603SJed Brown       for (PetscInt i = 0; i < npoints; i++) {
3053431e603SJed Brown         PetscInt p = points[2 * i];
3063431e603SJed Brown         if (p < vStart || vEnd <= p) continue;
3073431e603SJed Brown         Ijk loc = ZCodeSplit(vert_z[p - vStart]);
3083431e603SJed Brown         // Convention here matches DMPlexCreateCubeMesh_Internal
3093431e603SJed Brown         bc_count[0] += loc.i == 0;
3103431e603SJed Brown         bc_count[1] += loc.i == layout.vextent.i - 1;
3113431e603SJed Brown         bc_count[2] += loc.j == 0;
3123431e603SJed Brown         bc_count[3] += loc.j == layout.vextent.j - 1;
3133431e603SJed Brown         bc_count[4] += loc.k == 0;
3143431e603SJed Brown         bc_count[5] += loc.k == layout.vextent.k - 1;
3153e72e933SJed Brown       }
3163431e603SJed Brown       PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &npoints, &points));
3173431e603SJed Brown       for (PetscInt bc = 0, bc_match = 0; bc < 2 * dim; bc++) {
3183431e603SJed Brown         if (bc_count[bc] == PetscPowInt(2, dim - 1)) {
3193431e603SJed Brown           PetscAssert(bc_match == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face matches multiple face sets");
3203431e603SJed Brown           PetscCall(DMLabelSetValue(label, f, face_marker_dim[dim][bc]));
3213431e603SJed Brown           bc_match++;
3223431e603SJed Brown         }
3233431e603SJed Brown       }
3243431e603SJed Brown     }
3253431e603SJed Brown     // Ensure that the Coordinate DM has our new boundary labels
3263431e603SJed Brown     DM cdm;
3273431e603SJed Brown     PetscCall(DMGetCoordinateDM(dm, &cdm));
3283431e603SJed Brown     PetscCall(DMCopyLabels(dm, cdm, PETSC_COPY_VALUES, PETSC_FALSE, DM_COPY_LABELS_FAIL));
3293431e603SJed Brown   }
3303431e603SJed Brown   PetscCall(PetscFree(vert_z));
3313e72e933SJed Brown   PetscFunctionReturn(0);
3323e72e933SJed Brown }
333