Actual source code: plexcreate.c

  1: #define PETSCDM_DLL
  2: #include <petsc/private/dmpleximpl.h>
  3: #include <petsc/private/hashseti.h>
  4: #include <petscsf.h>
  5: #include <petscdmplextransform.h>
  6: #include <petscdmlabelephemeral.h>
  7: #include <petsc/private/kernels/blockmatmult.h>
  8: #include <petsc/private/kernels/blockinvert.h>

 10: PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;

 12: /* External function declarations here */
 13: static PetscErrorCode DMInitialize_Plex(DM dm);

 15: /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */
 16: PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout)
 17: {
 18:   const PetscReal         *maxCell, *Lstart, *L;
 19:   PetscBool                dist;
 20:   DMPlexReorderDefaultFlag reorder;

 22:   PetscFunctionBegin;
 23:   if (copyPeriodicity) {
 24:     PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L));
 25:     PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L));
 26:   }
 27:   PetscCall(DMPlexDistributeGetDefault(dmin, &dist));
 28:   PetscCall(DMPlexDistributeSetDefault(dmout, dist));
 29:   PetscCall(DMPlexReorderGetDefault(dmin, &reorder));
 30:   PetscCall(DMPlexReorderSetDefault(dmout, reorder));
 31:   ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation;
 32:   if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0));
 33:   PetscFunctionReturn(PETSC_SUCCESS);
 34: }

 36: /* Replace dm with the contents of ndm, and then destroy ndm
 37:    - Share the DM_Plex structure
 38:    - Share the coordinates
 39:    - Share the SF
 40: */
 41: PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm)
 42: {
 43:   PetscSF          sf;
 44:   DM               dmNew = *ndm, coordDM, coarseDM;
 45:   Vec              coords;
 46:   const PetscReal *maxCell, *Lstart, *L;
 47:   PetscInt         dim, cdim;

 49:   PetscFunctionBegin;
 50:   if (dm == dmNew) {
 51:     PetscCall(DMDestroy(ndm));
 52:     PetscFunctionReturn(PETSC_SUCCESS);
 53:   }
 54:   dm->setupcalled = dmNew->setupcalled;
 55:   PetscCall(DMGetDimension(dmNew, &dim));
 56:   PetscCall(DMSetDimension(dm, dim));
 57:   PetscCall(DMGetCoordinateDim(dmNew, &cdim));
 58:   PetscCall(DMSetCoordinateDim(dm, cdim));
 59:   PetscCall(DMGetPointSF(dmNew, &sf));
 60:   PetscCall(DMSetPointSF(dm, sf));
 61:   PetscCall(DMGetCoordinateDM(dmNew, &coordDM));
 62:   PetscCall(DMGetCoordinatesLocal(dmNew, &coords));
 63:   PetscCall(DMSetCoordinateDM(dm, coordDM));
 64:   PetscCall(DMSetCoordinatesLocal(dm, coords));
 65:   PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM));
 66:   PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords));
 67:   PetscCall(DMSetCellCoordinateDM(dm, coordDM));
 68:   PetscCall(DMSetCellCoordinatesLocal(dm, coords));
 69:   /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */
 70:   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
 71:   dm->coordinates[0].field            = dmNew->coordinates[0].field;
 72:   ((DM_Plex *)dmNew->data)->coordFunc = ((DM_Plex *)dm->data)->coordFunc;
 73:   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
 74:   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
 75:   PetscCall(DMDestroy_Plex(dm));
 76:   PetscCall(DMInitialize_Plex(dm));
 77:   dm->data = dmNew->data;
 78:   ((DM_Plex *)dmNew->data)->refct++;
 79:   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &sf));
 80:   PetscCall(DMPlexSetIsoperiodicFaceSF(dm, sf)); // for the compose function effect on dm
 81:   PetscCall(DMDestroyLabelLinkList_Internal(dm));
 82:   PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
 83:   PetscCall(DMGetCoarseDM(dmNew, &coarseDM));
 84:   PetscCall(DMSetCoarseDM(dm, coarseDM));
 85:   PetscCall(DMDestroy(ndm));
 86:   PetscFunctionReturn(PETSC_SUCCESS);
 87: }

 89: /* Swap dm with the contents of dmNew
 90:    - Swap the DM_Plex structure
 91:    - Swap the coordinates
 92:    - Swap the point PetscSF
 93: */
 94: static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
 95: {
 96:   DM          coordDMA, coordDMB;
 97:   Vec         coordsA, coordsB;
 98:   PetscSF     sfA, sfB;
 99:   DMField     fieldTmp;
100:   void       *tmp;
101:   DMLabelLink listTmp;
102:   DMLabel     depthTmp;
103:   PetscInt    tmpI;

105:   PetscFunctionBegin;
106:   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
107:   PetscCall(DMGetPointSF(dmA, &sfA));
108:   PetscCall(DMGetPointSF(dmB, &sfB));
109:   PetscCall(PetscObjectReference((PetscObject)sfA));
110:   PetscCall(DMSetPointSF(dmA, sfB));
111:   PetscCall(DMSetPointSF(dmB, sfA));
112:   PetscCall(PetscObjectDereference((PetscObject)sfA));

114:   PetscCall(DMGetCoordinateDM(dmA, &coordDMA));
115:   PetscCall(DMGetCoordinateDM(dmB, &coordDMB));
116:   PetscCall(PetscObjectReference((PetscObject)coordDMA));
117:   PetscCall(DMSetCoordinateDM(dmA, coordDMB));
118:   PetscCall(DMSetCoordinateDM(dmB, coordDMA));
119:   PetscCall(PetscObjectDereference((PetscObject)coordDMA));

121:   PetscCall(DMGetCoordinatesLocal(dmA, &coordsA));
122:   PetscCall(DMGetCoordinatesLocal(dmB, &coordsB));
123:   PetscCall(PetscObjectReference((PetscObject)coordsA));
124:   PetscCall(DMSetCoordinatesLocal(dmA, coordsB));
125:   PetscCall(DMSetCoordinatesLocal(dmB, coordsA));
126:   PetscCall(PetscObjectDereference((PetscObject)coordsA));

128:   PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA));
129:   PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB));
130:   PetscCall(PetscObjectReference((PetscObject)coordDMA));
131:   PetscCall(DMSetCellCoordinateDM(dmA, coordDMB));
132:   PetscCall(DMSetCellCoordinateDM(dmB, coordDMA));
133:   PetscCall(PetscObjectDereference((PetscObject)coordDMA));

135:   PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA));
136:   PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB));
137:   PetscCall(PetscObjectReference((PetscObject)coordsA));
138:   PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB));
139:   PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA));
140:   PetscCall(PetscObjectDereference((PetscObject)coordsA));

142:   fieldTmp                  = dmA->coordinates[0].field;
143:   dmA->coordinates[0].field = dmB->coordinates[0].field;
144:   dmB->coordinates[0].field = fieldTmp;
145:   fieldTmp                  = dmA->coordinates[1].field;
146:   dmA->coordinates[1].field = dmB->coordinates[1].field;
147:   dmB->coordinates[1].field = fieldTmp;
148:   tmp                       = dmA->data;
149:   dmA->data                 = dmB->data;
150:   dmB->data                 = tmp;
151:   listTmp                   = dmA->labels;
152:   dmA->labels               = dmB->labels;
153:   dmB->labels               = listTmp;
154:   depthTmp                  = dmA->depthLabel;
155:   dmA->depthLabel           = dmB->depthLabel;
156:   dmB->depthLabel           = depthTmp;
157:   depthTmp                  = dmA->celltypeLabel;
158:   dmA->celltypeLabel        = dmB->celltypeLabel;
159:   dmB->celltypeLabel        = depthTmp;
160:   tmpI                      = dmA->levelup;
161:   dmA->levelup              = dmB->levelup;
162:   dmB->levelup              = tmpI;
163:   PetscFunctionReturn(PETSC_SUCCESS);
164: }

166: PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm)
167: {
168:   DM idm;

170:   PetscFunctionBegin;
171:   PetscCall(DMPlexInterpolate(dm, &idm));
172:   PetscCall(DMPlexCopyCoordinates(dm, idm));
173:   PetscCall(DMPlexReplace_Internal(dm, &idm));
174:   PetscFunctionReturn(PETSC_SUCCESS);
175: }

177: /*@C
178:   DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates

180:   Collective on dm

182:   Input Parameters:
183: + DM        - The DM
184: . degree    - The degree of the finite element or PETSC_DECIDE
185: - coordFunc - An optional function to map new points from refinement to the surface

187:   Level: advanced

189: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscPointFunc`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()`
190: @*/
191: PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscPointFunc coordFunc)
192: {
193:   DM_Plex     *mesh = (DM_Plex *)dm->data;
194:   DM           cdm;
195:   PetscDS      cds;
196:   PetscFE      fe;
197:   PetscClassId id;

199:   PetscFunctionBegin;
200:   PetscCall(DMGetCoordinateDM(dm, &cdm));
201:   PetscCall(DMGetDS(cdm, &cds));
202:   PetscCall(PetscDSGetDiscretization(cds, 0, (PetscObject *)&fe));
203:   PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
204:   if (id != PETSCFE_CLASSID) {
205:     PetscInt dim, dE, qorder;

207:     PetscCall(DMGetDimension(dm, &dim));
208:     PetscCall(DMGetCoordinateDim(dm, &dE));
209:     qorder = degree;
210:     PetscObjectOptionsBegin((PetscObject)cdm);
211:     PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0));
212:     PetscOptionsEnd();
213:     if (degree == PETSC_DECIDE) fe = NULL;
214:     else {
215:       DMPolytopeType ct;
216:       PetscInt       cStart, cEnd, ctTmp;

218:       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
219:       // Want to match cell types
220:       if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct));
221:       else ct = DM_POLYTOPE_UNKNOWN;
222:       ctTmp = (PetscInt)ct;
223:       PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &ctTmp, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm)));
224:       ct = (DMPolytopeType)ctTmp;
225:       // Work around current bug
226:       if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) fe = NULL;
227:       else PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe));
228:     }
229:     if (fe) PetscCall(DMProjectCoordinates(dm, fe));
230:     PetscCall(PetscFEDestroy(&fe));
231:   }
232:   mesh->coordFunc = coordFunc;
233:   PetscFunctionReturn(PETSC_SUCCESS);
234: }

236: /*@
237:   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.

239:   Collective

241:   Input Parameters:
242: + comm - The communicator for the `DM` object
243: . dim - The spatial dimension
244: . simplex - Flag for simplicial cells, otherwise they are tensor product cells
245: . interpolate - Flag to create intermediate mesh pieces (edges, faces)
246: - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell

248:   Output Parameter:
249: . dm - The `DM` object

251:   Level: beginner

253: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()`
254: @*/
255: PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm)
256: {
257:   DM          dm;
258:   PetscMPIInt rank;

260:   PetscFunctionBegin;
261:   PetscCall(DMCreate(comm, &dm));
262:   PetscCall(DMSetType(dm, DMPLEX));
263:   PetscCall(DMSetDimension(dm, dim));
264:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
265:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
266:   switch (dim) {
267:   case 2:
268:     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular"));
269:     else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral"));
270:     break;
271:   case 3:
272:     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral"));
273:     else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral"));
274:     break;
275:   default:
276:     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
277:   }
278:   if (rank) {
279:     PetscInt numPoints[2] = {0, 0};
280:     PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL));
281:   } else {
282:     switch (dim) {
283:     case 2:
284:       if (simplex) {
285:         PetscInt    numPoints[2]        = {4, 2};
286:         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
287:         PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
288:         PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
289:         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};

291:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
292:       } else {
293:         PetscInt    numPoints[2]        = {6, 2};
294:         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
295:         PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
296:         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
297:         PetscScalar vertexCoords[12]    = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5};

299:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
300:       }
301:       break;
302:     case 3:
303:       if (simplex) {
304:         PetscInt    numPoints[2]        = {5, 2};
305:         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
306:         PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
307:         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
308:         PetscScalar vertexCoords[15]    = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};

310:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
311:       } else {
312:         PetscInt    numPoints[2]         = {12, 2};
313:         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
314:         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
315:         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
316:         PetscScalar vertexCoords[36]     = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5};

318:         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
319:       }
320:       break;
321:     default:
322:       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
323:     }
324:   }
325:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
326:   *newdm = dm;
327:   if (refinementLimit > 0.0) {
328:     DM          rdm;
329:     const char *name;

331:     PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE));
332:     PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit));
333:     PetscCall(DMRefine(*newdm, comm, &rdm));
334:     PetscCall(PetscObjectGetName((PetscObject)*newdm, &name));
335:     PetscCall(PetscObjectSetName((PetscObject)rdm, name));
336:     PetscCall(DMDestroy(newdm));
337:     *newdm = rdm;
338:   }
339:   if (interpolate) {
340:     DM idm;

342:     PetscCall(DMPlexInterpolate(*newdm, &idm));
343:     PetscCall(DMDestroy(newdm));
344:     *newdm = idm;
345:   }
346:   PetscFunctionReturn(PETSC_SUCCESS);
347: }

349: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
350: {
351:   const PetscInt numVertices    = 2;
352:   PetscInt       markerRight    = 1;
353:   PetscInt       markerLeft     = 1;
354:   PetscBool      markerSeparate = PETSC_FALSE;
355:   Vec            coordinates;
356:   PetscSection   coordSection;
357:   PetscScalar   *coords;
358:   PetscInt       coordSize;
359:   PetscMPIInt    rank;
360:   PetscInt       cdim = 1, v;

362:   PetscFunctionBegin;
363:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
364:   if (markerSeparate) {
365:     markerRight = 2;
366:     markerLeft  = 1;
367:   }
368:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
369:   if (rank == 0) {
370:     PetscCall(DMPlexSetChart(dm, 0, numVertices));
371:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
372:     PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft));
373:     PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight));
374:   }
375:   PetscCall(DMPlexSymmetrize(dm));
376:   PetscCall(DMPlexStratify(dm));
377:   /* Build coordinates */
378:   PetscCall(DMSetCoordinateDim(dm, cdim));
379:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
380:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
381:   PetscCall(PetscSectionSetChart(coordSection, 0, numVertices));
382:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
383:   for (v = 0; v < numVertices; ++v) {
384:     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
385:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
386:   }
387:   PetscCall(PetscSectionSetUp(coordSection));
388:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
389:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
390:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
391:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
392:   PetscCall(VecSetBlockSize(coordinates, cdim));
393:   PetscCall(VecSetType(coordinates, VECSTANDARD));
394:   PetscCall(VecGetArray(coordinates, &coords));
395:   coords[0] = lower[0];
396:   coords[1] = upper[0];
397:   PetscCall(VecRestoreArray(coordinates, &coords));
398:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
399:   PetscCall(VecDestroy(&coordinates));
400:   PetscFunctionReturn(PETSC_SUCCESS);
401: }

403: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
404: {
405:   const PetscInt numVertices    = (edges[0] + 1) * (edges[1] + 1);
406:   const PetscInt numEdges       = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1];
407:   PetscInt       markerTop      = 1;
408:   PetscInt       markerBottom   = 1;
409:   PetscInt       markerRight    = 1;
410:   PetscInt       markerLeft     = 1;
411:   PetscBool      markerSeparate = PETSC_FALSE;
412:   Vec            coordinates;
413:   PetscSection   coordSection;
414:   PetscScalar   *coords;
415:   PetscInt       coordSize;
416:   PetscMPIInt    rank;
417:   PetscInt       v, vx, vy;

419:   PetscFunctionBegin;
420:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
421:   if (markerSeparate) {
422:     markerTop    = 3;
423:     markerBottom = 1;
424:     markerRight  = 2;
425:     markerLeft   = 4;
426:   }
427:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
428:   if (rank == 0) {
429:     PetscInt e, ex, ey;

431:     PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices));
432:     for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
433:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
434:     for (vx = 0; vx <= edges[0]; vx++) {
435:       for (ey = 0; ey < edges[1]; ey++) {
436:         PetscInt edge   = vx * edges[1] + ey + edges[0] * (edges[1] + 1);
437:         PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges;
438:         PetscInt cone[2];

440:         cone[0] = vertex;
441:         cone[1] = vertex + edges[0] + 1;
442:         PetscCall(DMPlexSetCone(dm, edge, cone));
443:         if (vx == edges[0]) {
444:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
445:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
446:           if (ey == edges[1] - 1) {
447:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
448:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight));
449:           }
450:         } else if (vx == 0) {
451:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
452:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
453:           if (ey == edges[1] - 1) {
454:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
455:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft));
456:           }
457:         }
458:       }
459:     }
460:     for (vy = 0; vy <= edges[1]; vy++) {
461:       for (ex = 0; ex < edges[0]; ex++) {
462:         PetscInt edge   = vy * edges[0] + ex;
463:         PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges;
464:         PetscInt cone[2];

466:         cone[0] = vertex;
467:         cone[1] = vertex + 1;
468:         PetscCall(DMPlexSetCone(dm, edge, cone));
469:         if (vy == edges[1]) {
470:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
471:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
472:           if (ex == edges[0] - 1) {
473:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
474:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop));
475:           }
476:         } else if (vy == 0) {
477:           PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
478:           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
479:           if (ex == edges[0] - 1) {
480:             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
481:             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom));
482:           }
483:         }
484:       }
485:     }
486:   }
487:   PetscCall(DMPlexSymmetrize(dm));
488:   PetscCall(DMPlexStratify(dm));
489:   /* Build coordinates */
490:   PetscCall(DMSetCoordinateDim(dm, 2));
491:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
492:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
493:   PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices));
494:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
495:   for (v = numEdges; v < numEdges + numVertices; ++v) {
496:     PetscCall(PetscSectionSetDof(coordSection, v, 2));
497:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
498:   }
499:   PetscCall(PetscSectionSetUp(coordSection));
500:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
501:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
502:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
503:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
504:   PetscCall(VecSetBlockSize(coordinates, 2));
505:   PetscCall(VecSetType(coordinates, VECSTANDARD));
506:   PetscCall(VecGetArray(coordinates, &coords));
507:   for (vy = 0; vy <= edges[1]; ++vy) {
508:     for (vx = 0; vx <= edges[0]; ++vx) {
509:       coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx;
510:       coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy;
511:     }
512:   }
513:   PetscCall(VecRestoreArray(coordinates, &coords));
514:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
515:   PetscCall(VecDestroy(&coordinates));
516:   PetscFunctionReturn(PETSC_SUCCESS);
517: }

519: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
520: {
521:   PetscInt     vertices[3], numVertices;
522:   PetscInt     numFaces       = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2];
523:   PetscInt     markerTop      = 1;
524:   PetscInt     markerBottom   = 1;
525:   PetscInt     markerFront    = 1;
526:   PetscInt     markerBack     = 1;
527:   PetscInt     markerRight    = 1;
528:   PetscInt     markerLeft     = 1;
529:   PetscBool    markerSeparate = PETSC_FALSE;
530:   Vec          coordinates;
531:   PetscSection coordSection;
532:   PetscScalar *coords;
533:   PetscInt     coordSize;
534:   PetscMPIInt  rank;
535:   PetscInt     v, vx, vy, vz;
536:   PetscInt     voffset, iface = 0, cone[4];

538:   PetscFunctionBegin;
539:   PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
540:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
541:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
542:   if (markerSeparate) {
543:     markerBottom = 1;
544:     markerTop    = 2;
545:     markerFront  = 3;
546:     markerBack   = 4;
547:     markerRight  = 5;
548:     markerLeft   = 6;
549:   }
550:   vertices[0] = faces[0] + 1;
551:   vertices[1] = faces[1] + 1;
552:   vertices[2] = faces[2] + 1;
553:   numVertices = vertices[0] * vertices[1] * vertices[2];
554:   if (rank == 0) {
555:     PetscInt f;

557:     PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices));
558:     for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
559:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */

561:     /* Side 0 (Top) */
562:     for (vy = 0; vy < faces[1]; vy++) {
563:       for (vx = 0; vx < faces[0]; vx++) {
564:         voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx;
565:         cone[0] = voffset;
566:         cone[1] = voffset + 1;
567:         cone[2] = voffset + vertices[0] + 1;
568:         cone[3] = voffset + vertices[0];
569:         PetscCall(DMPlexSetCone(dm, iface, cone));
570:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop));
571:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop));
572:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop));
573:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop));
574:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop));
575:         iface++;
576:       }
577:     }

579:     /* Side 1 (Bottom) */
580:     for (vy = 0; vy < faces[1]; vy++) {
581:       for (vx = 0; vx < faces[0]; vx++) {
582:         voffset = numFaces + vy * (faces[0] + 1) + vx;
583:         cone[0] = voffset + 1;
584:         cone[1] = voffset;
585:         cone[2] = voffset + vertices[0];
586:         cone[3] = voffset + vertices[0] + 1;
587:         PetscCall(DMPlexSetCone(dm, iface, cone));
588:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom));
589:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom));
590:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom));
591:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom));
592:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom));
593:         iface++;
594:       }
595:     }

597:     /* Side 2 (Front) */
598:     for (vz = 0; vz < faces[2]; vz++) {
599:       for (vx = 0; vx < faces[0]; vx++) {
600:         voffset = numFaces + vz * vertices[0] * vertices[1] + vx;
601:         cone[0] = voffset;
602:         cone[1] = voffset + 1;
603:         cone[2] = voffset + vertices[0] * vertices[1] + 1;
604:         cone[3] = voffset + vertices[0] * vertices[1];
605:         PetscCall(DMPlexSetCone(dm, iface, cone));
606:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront));
607:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront));
608:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront));
609:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront));
610:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront));
611:         iface++;
612:       }
613:     }

615:     /* Side 3 (Back) */
616:     for (vz = 0; vz < faces[2]; vz++) {
617:       for (vx = 0; vx < faces[0]; vx++) {
618:         voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx;
619:         cone[0] = voffset + vertices[0] * vertices[1];
620:         cone[1] = voffset + vertices[0] * vertices[1] + 1;
621:         cone[2] = voffset + 1;
622:         cone[3] = voffset;
623:         PetscCall(DMPlexSetCone(dm, iface, cone));
624:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack));
625:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack));
626:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack));
627:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack));
628:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack));
629:         iface++;
630:       }
631:     }

633:     /* Side 4 (Left) */
634:     for (vz = 0; vz < faces[2]; vz++) {
635:       for (vy = 0; vy < faces[1]; vy++) {
636:         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0];
637:         cone[0] = voffset;
638:         cone[1] = voffset + vertices[0] * vertices[1];
639:         cone[2] = voffset + vertices[0] * vertices[1] + vertices[0];
640:         cone[3] = voffset + vertices[0];
641:         PetscCall(DMPlexSetCone(dm, iface, cone));
642:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft));
643:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft));
644:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft));
645:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft));
646:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft));
647:         iface++;
648:       }
649:     }

651:     /* Side 5 (Right) */
652:     for (vz = 0; vz < faces[2]; vz++) {
653:       for (vy = 0; vy < faces[1]; vy++) {
654:         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0];
655:         cone[0] = voffset + vertices[0] * vertices[1];
656:         cone[1] = voffset;
657:         cone[2] = voffset + vertices[0];
658:         cone[3] = voffset + vertices[0] * vertices[1] + vertices[0];
659:         PetscCall(DMPlexSetCone(dm, iface, cone));
660:         PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight));
661:         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight));
662:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight));
663:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight));
664:         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight));
665:         iface++;
666:       }
667:     }
668:   }
669:   PetscCall(DMPlexSymmetrize(dm));
670:   PetscCall(DMPlexStratify(dm));
671:   /* Build coordinates */
672:   PetscCall(DMSetCoordinateDim(dm, 3));
673:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
674:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
675:   PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices));
676:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
677:   for (v = numFaces; v < numFaces + numVertices; ++v) {
678:     PetscCall(PetscSectionSetDof(coordSection, v, 3));
679:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
680:   }
681:   PetscCall(PetscSectionSetUp(coordSection));
682:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
683:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
684:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
685:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
686:   PetscCall(VecSetBlockSize(coordinates, 3));
687:   PetscCall(VecSetType(coordinates, VECSTANDARD));
688:   PetscCall(VecGetArray(coordinates, &coords));
689:   for (vz = 0; vz <= faces[2]; ++vz) {
690:     for (vy = 0; vy <= faces[1]; ++vy) {
691:       for (vx = 0; vx <= faces[0]; ++vx) {
692:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx;
693:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy;
694:         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz;
695:       }
696:     }
697:   }
698:   PetscCall(VecRestoreArray(coordinates, &coords));
699:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
700:   PetscCall(VecDestroy(&coordinates));
701:   PetscFunctionReturn(PETSC_SUCCESS);
702: }

704: static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate)
705: {
706:   PetscFunctionBegin;
708:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
709:   PetscCall(DMSetDimension(dm, dim - 1));
710:   PetscCall(DMSetCoordinateDim(dm, dim));
711:   switch (dim) {
712:   case 1:
713:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces));
714:     break;
715:   case 2:
716:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces));
717:     break;
718:   case 3:
719:     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces));
720:     break;
721:   default:
722:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim);
723:   }
724:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
725:   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
726:   PetscFunctionReturn(PETSC_SUCCESS);
727: }

729: /*@C
730:   DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra).

732:   Collective

734:   Input Parameters:
735: + comm        - The communicator for the `DM` object
736: . dim         - The spatial dimension of the box, so the resulting mesh is has dimension dim-1
737: . faces       - Number of faces per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
738: . lower       - The lower left corner, or NULL for (0, 0, 0)
739: . upper       - The upper right corner, or NULL for (1, 1, 1)
740: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

742:   Output Parameter:
743: . dm  - The `DM` object

745:   Level: beginner

747: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()`
748: @*/
749: PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
750: {
751:   PetscInt  fac[3] = {1, 1, 1};
752:   PetscReal low[3] = {0, 0, 0};
753:   PetscReal upp[3] = {1, 1, 1};

755:   PetscFunctionBegin;
756:   PetscCall(DMCreate(comm, dm));
757:   PetscCall(DMSetType(*dm, DMPLEX));
758:   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate));
759:   PetscFunctionReturn(PETSC_SUCCESS);
760: }

762: static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd)
763: {
764:   PetscInt     i, fStart, fEnd, numCells = 0, numVerts = 0;
765:   PetscInt     numPoints[2], *coneSize, *cones, *coneOrientations;
766:   PetscScalar *vertexCoords;
767:   PetscReal    L, maxCell;
768:   PetscBool    markerSeparate = PETSC_FALSE;
769:   PetscInt     markerLeft = 1, faceMarkerLeft = 1;
770:   PetscInt     markerRight = 1, faceMarkerRight = 2;
771:   PetscBool    wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
772:   PetscMPIInt  rank;

774:   PetscFunctionBegin;

777:   PetscCall(DMSetDimension(dm, 1));
778:   PetscCall(DMCreateLabel(dm, "marker"));
779:   PetscCall(DMCreateLabel(dm, "Face Sets"));

781:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
782:   if (rank == 0) numCells = segments;
783:   if (rank == 0) numVerts = segments + (wrap ? 0 : 1);

785:   numPoints[0] = numVerts;
786:   numPoints[1] = numCells;
787:   PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords));
788:   PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts));
789:   for (i = 0; i < numCells; ++i) coneSize[i] = 2;
790:   for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0;
791:   for (i = 0; i < numCells; ++i) {
792:     cones[2 * i]     = numCells + i % numVerts;
793:     cones[2 * i + 1] = numCells + (i + 1) % numVerts;
794:   }
795:   for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells);
796:   PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
797:   PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords));

799:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
800:   if (markerSeparate) {
801:     markerLeft  = faceMarkerLeft;
802:     markerRight = faceMarkerRight;
803:   }
804:   if (!wrap && rank == 0) {
805:     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
806:     PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft));
807:     PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight));
808:     PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft));
809:     PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight));
810:   }
811:   if (wrap) {
812:     L       = upper - lower;
813:     maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments));
814:     PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L));
815:   }
816:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
817:   PetscFunctionReturn(PETSC_SUCCESS);
818: }

820: static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
821: {
822:   DM      boundary, vol;
823:   DMLabel bdlabel;

825:   PetscFunctionBegin;
827:   for (PetscInt i = 0; i < dim; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes");
828:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary));
829:   PetscCall(DMSetType(boundary, DMPLEX));
830:   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE));
831:   PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol));
832:   PetscCall(DMGetLabel(vol, "marker", &bdlabel));
833:   if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel));
834:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol));
835:   PetscCall(DMPlexReplace_Internal(dm, &vol));
836:   PetscCall(DMDestroy(&boundary));
837:   PetscFunctionReturn(PETSC_SUCCESS);
838: }

840: static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
841: {
842:   DMLabel     cutLabel  = NULL;
843:   PetscInt    markerTop = 1, faceMarkerTop = 1;
844:   PetscInt    markerBottom = 1, faceMarkerBottom = 1;
845:   PetscInt    markerFront = 1, faceMarkerFront = 1;
846:   PetscInt    markerBack = 1, faceMarkerBack = 1;
847:   PetscInt    markerRight = 1, faceMarkerRight = 1;
848:   PetscInt    markerLeft = 1, faceMarkerLeft = 1;
849:   PetscInt    dim;
850:   PetscBool   markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
851:   PetscMPIInt rank;

853:   PetscFunctionBegin;
854:   PetscCall(DMGetDimension(dm, &dim));
855:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
856:   PetscCall(DMCreateLabel(dm, "marker"));
857:   PetscCall(DMCreateLabel(dm, "Face Sets"));
858:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
859:   if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST || bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST || bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) {
860:     if (cutMarker) {
861:       PetscCall(DMCreateLabel(dm, "periodic_cut"));
862:       PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
863:     }
864:   }
865:   switch (dim) {
866:   case 2:
867:     faceMarkerTop    = 3;
868:     faceMarkerBottom = 1;
869:     faceMarkerRight  = 2;
870:     faceMarkerLeft   = 4;
871:     break;
872:   case 3:
873:     faceMarkerBottom = 1;
874:     faceMarkerTop    = 2;
875:     faceMarkerFront  = 3;
876:     faceMarkerBack   = 4;
877:     faceMarkerRight  = 5;
878:     faceMarkerLeft   = 6;
879:     break;
880:   default:
881:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
882:   }
883:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
884:   if (markerSeparate) {
885:     markerBottom = faceMarkerBottom;
886:     markerTop    = faceMarkerTop;
887:     markerFront  = faceMarkerFront;
888:     markerBack   = faceMarkerBack;
889:     markerRight  = faceMarkerRight;
890:     markerLeft   = faceMarkerLeft;
891:   }
892:   {
893:     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
894:     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
895:     const PetscInt numZEdges    = rank == 0 ? edges[2] : 0;
896:     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0;
897:     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0;
898:     const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0;
899:     const PetscInt numCells     = numXEdges * numYEdges * numZEdges;
900:     const PetscInt numXFaces    = numYEdges * numZEdges;
901:     const PetscInt numYFaces    = numXEdges * numZEdges;
902:     const PetscInt numZFaces    = numXEdges * numYEdges;
903:     const PetscInt numTotXFaces = numXVertices * numXFaces;
904:     const PetscInt numTotYFaces = numYVertices * numYFaces;
905:     const PetscInt numTotZFaces = numZVertices * numZFaces;
906:     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
907:     const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices;
908:     const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices;
909:     const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices;
910:     const PetscInt numVertices  = numXVertices * numYVertices * numZVertices;
911:     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
912:     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
913:     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
914:     const PetscInt firstYFace   = firstXFace + numTotXFaces;
915:     const PetscInt firstZFace   = firstYFace + numTotYFaces;
916:     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
917:     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
918:     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
919:     Vec            coordinates;
920:     PetscSection   coordSection;
921:     PetscScalar   *coords;
922:     PetscInt       coordSize;
923:     PetscInt       v, vx, vy, vz;
924:     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;

926:     PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices));
927:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
928:     for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
929:     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
930:     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
931:     /* Build cells */
932:     for (fz = 0; fz < numZEdges; ++fz) {
933:       for (fy = 0; fy < numYEdges; ++fy) {
934:         for (fx = 0; fx < numXEdges; ++fx) {
935:           PetscInt cell  = (fz * numYEdges + fy) * numXEdges + fx;
936:           PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
937:           PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices);
938:           PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
939:           PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices);
940:           PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
941:           PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices);
942:           /* B,  T,  F,  K,  R,  L */
943:           PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */
944:           PetscInt cone[6];

946:           /* no boundary twisting in 3D */
947:           cone[0] = faceB;
948:           cone[1] = faceT;
949:           cone[2] = faceF;
950:           cone[3] = faceK;
951:           cone[4] = faceR;
952:           cone[5] = faceL;
953:           PetscCall(DMPlexSetCone(dm, cell, cone));
954:           PetscCall(DMPlexSetConeOrientation(dm, cell, ornt));
955:           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
956:           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
957:           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
958:         }
959:       }
960:     }
961:     /* Build x faces */
962:     for (fz = 0; fz < numZEdges; ++fz) {
963:       for (fy = 0; fy < numYEdges; ++fy) {
964:         for (fx = 0; fx < numXVertices; ++fx) {
965:           PetscInt face    = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
966:           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
967:           PetscInt edgeR   = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz;
968:           PetscInt edgeB   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
969:           PetscInt edgeT   = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy;
970:           PetscInt ornt[4] = {0, 0, -1, -1};
971:           PetscInt cone[4];

973:           if (dim == 3) {
974:             /* markers */
975:             if (bdX != DM_BOUNDARY_PERIODIC) {
976:               if (fx == numXVertices - 1) {
977:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight));
978:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight));
979:               } else if (fx == 0) {
980:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft));
981:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft));
982:               }
983:             }
984:           }
985:           cone[0] = edgeB;
986:           cone[1] = edgeR;
987:           cone[2] = edgeT;
988:           cone[3] = edgeL;
989:           PetscCall(DMPlexSetCone(dm, face, cone));
990:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
991:         }
992:       }
993:     }
994:     /* Build y faces */
995:     for (fz = 0; fz < numZEdges; ++fz) {
996:       for (fx = 0; fx < numXEdges; ++fx) {
997:         for (fy = 0; fy < numYVertices; ++fy) {
998:           PetscInt face    = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
999:           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
1000:           PetscInt edgeR   = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz;
1001:           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1002:           PetscInt edgeT   = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx;
1003:           PetscInt ornt[4] = {0, 0, -1, -1};
1004:           PetscInt cone[4];

1006:           if (dim == 3) {
1007:             /* markers */
1008:             if (bdY != DM_BOUNDARY_PERIODIC) {
1009:               if (fy == numYVertices - 1) {
1010:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack));
1011:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack));
1012:               } else if (fy == 0) {
1013:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront));
1014:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront));
1015:               }
1016:             }
1017:           }
1018:           cone[0] = edgeB;
1019:           cone[1] = edgeR;
1020:           cone[2] = edgeT;
1021:           cone[3] = edgeL;
1022:           PetscCall(DMPlexSetCone(dm, face, cone));
1023:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1024:         }
1025:       }
1026:     }
1027:     /* Build z faces */
1028:     for (fy = 0; fy < numYEdges; ++fy) {
1029:       for (fx = 0; fx < numXEdges; ++fx) {
1030:         for (fz = 0; fz < numZVertices; fz++) {
1031:           PetscInt face    = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
1032:           PetscInt edgeL   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
1033:           PetscInt edgeR   = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy;
1034:           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1035:           PetscInt edgeT   = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx;
1036:           PetscInt ornt[4] = {0, 0, -1, -1};
1037:           PetscInt cone[4];

1039:           if (dim == 2) {
1040:             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) {
1041:               edgeR += numYEdges - 1 - 2 * fy;
1042:               ornt[1] = -1;
1043:             }
1044:             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) {
1045:               edgeT += numXEdges - 1 - 2 * fx;
1046:               ornt[2] = 0;
1047:             }
1048:             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1049:             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1050:           } else {
1051:             /* markers */
1052:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1053:               if (fz == numZVertices - 1) {
1054:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop));
1055:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop));
1056:               } else if (fz == 0) {
1057:                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom));
1058:                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom));
1059:               }
1060:             }
1061:           }
1062:           cone[0] = edgeB;
1063:           cone[1] = edgeR;
1064:           cone[2] = edgeT;
1065:           cone[3] = edgeL;
1066:           PetscCall(DMPlexSetCone(dm, face, cone));
1067:           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1068:         }
1069:       }
1070:     }
1071:     /* Build Z edges*/
1072:     for (vy = 0; vy < numYVertices; vy++) {
1073:       for (vx = 0; vx < numXVertices; vx++) {
1074:         for (ez = 0; ez < numZEdges; ez++) {
1075:           const PetscInt edge    = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez;
1076:           const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx;
1077:           const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx;
1078:           PetscInt       cone[2];

1080:           cone[0] = vertexB;
1081:           cone[1] = vertexT;
1082:           PetscCall(DMPlexSetCone(dm, edge, cone));
1083:           if (dim == 3) {
1084:             if (bdX != DM_BOUNDARY_PERIODIC) {
1085:               if (vx == numXVertices - 1) {
1086:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1087:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1088:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1089:               } else if (vx == 0) {
1090:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1091:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1092:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1093:               }
1094:             }
1095:             if (bdY != DM_BOUNDARY_PERIODIC) {
1096:               if (vy == numYVertices - 1) {
1097:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1098:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1099:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1100:               } else if (vy == 0) {
1101:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1102:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1103:                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1104:               }
1105:             }
1106:           }
1107:         }
1108:       }
1109:     }
1110:     /* Build Y edges*/
1111:     for (vz = 0; vz < numZVertices; vz++) {
1112:       for (vx = 0; vx < numXVertices; vx++) {
1113:         for (ey = 0; ey < numYEdges; ey++) {
1114:           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx;
1115:           const PetscInt edge    = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey;
1116:           const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx;
1117:           const PetscInt vertexK = firstVertex + nextv;
1118:           PetscInt       cone[2];

1120:           cone[0] = vertexF;
1121:           cone[1] = vertexK;
1122:           PetscCall(DMPlexSetCone(dm, edge, cone));
1123:           if (dim == 2) {
1124:             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1125:               if (vx == numXVertices - 1) {
1126:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1127:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1128:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1129:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1130:               } else if (vx == 0) {
1131:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1132:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1133:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1134:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1135:               }
1136:             } else {
1137:               if (vx == 0 && cutLabel) {
1138:                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1139:                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1140:                 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1141:               }
1142:             }
1143:           } else {
1144:             if (bdX != DM_BOUNDARY_PERIODIC) {
1145:               if (vx == numXVertices - 1) {
1146:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1147:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1148:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1149:               } else if (vx == 0) {
1150:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1151:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1152:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1153:               }
1154:             }
1155:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1156:               if (vz == numZVertices - 1) {
1157:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1158:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1159:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1160:               } else if (vz == 0) {
1161:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1162:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1163:                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1164:               }
1165:             }
1166:           }
1167:         }
1168:       }
1169:     }
1170:     /* Build X edges*/
1171:     for (vz = 0; vz < numZVertices; vz++) {
1172:       for (vy = 0; vy < numYVertices; vy++) {
1173:         for (ex = 0; ex < numXEdges; ex++) {
1174:           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices;
1175:           const PetscInt edge    = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex;
1176:           const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex;
1177:           const PetscInt vertexR = firstVertex + nextv;
1178:           PetscInt       cone[2];

1180:           cone[0] = vertexL;
1181:           cone[1] = vertexR;
1182:           PetscCall(DMPlexSetCone(dm, edge, cone));
1183:           if (dim == 2) {
1184:             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1185:               if (vy == numYVertices - 1) {
1186:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1187:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1188:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1189:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1190:               } else if (vy == 0) {
1191:                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1192:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1193:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1194:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1195:               }
1196:             } else {
1197:               if (vy == 0 && cutLabel) {
1198:                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1199:                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1200:                 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1201:               }
1202:             }
1203:           } else {
1204:             if (bdY != DM_BOUNDARY_PERIODIC) {
1205:               if (vy == numYVertices - 1) {
1206:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1207:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1208:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1209:               } else if (vy == 0) {
1210:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1211:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1212:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1213:               }
1214:             }
1215:             if (bdZ != DM_BOUNDARY_PERIODIC) {
1216:               if (vz == numZVertices - 1) {
1217:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1218:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1219:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1220:               } else if (vz == 0) {
1221:                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1222:                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1223:                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1224:               }
1225:             }
1226:           }
1227:         }
1228:       }
1229:     }
1230:     PetscCall(DMPlexSymmetrize(dm));
1231:     PetscCall(DMPlexStratify(dm));
1232:     /* Build coordinates */
1233:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1234:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1235:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1236:     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1237:     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1238:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
1239:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1240:     }
1241:     PetscCall(PetscSectionSetUp(coordSection));
1242:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1243:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1244:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1245:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1246:     PetscCall(VecSetBlockSize(coordinates, dim));
1247:     PetscCall(VecSetType(coordinates, VECSTANDARD));
1248:     PetscCall(VecGetArray(coordinates, &coords));
1249:     for (vz = 0; vz < numZVertices; ++vz) {
1250:       for (vy = 0; vy < numYVertices; ++vy) {
1251:         for (vx = 0; vx < numXVertices; ++vx) {
1252:           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1253:           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1254:           if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz;
1255:         }
1256:       }
1257:     }
1258:     PetscCall(VecRestoreArray(coordinates, &coords));
1259:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1260:     PetscCall(VecDestroy(&coordinates));
1261:   }
1262:   PetscFunctionReturn(PETSC_SUCCESS);
1263: }

1265: static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1266: {
1267:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1268:   PetscInt       fac[3] = {0, 0, 0}, d;

1270:   PetscFunctionBegin;
1273:   PetscCall(DMSetDimension(dm, dim));
1274:   for (d = 0; d < dim; ++d) {
1275:     fac[d] = faces[d];
1276:     bdt[d] = periodicity[d];
1277:   }
1278:   PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2]));
1279:   if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST || periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST || (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) {
1280:     PetscReal L[3]       = {-1., -1., 0.};
1281:     PetscReal maxCell[3] = {-1., -1., 0.};

1283:     for (d = 0; d < dim; ++d) {
1284:       if (periodicity[d] != DM_BOUNDARY_NONE) {
1285:         L[d]       = upper[d] - lower[d];
1286:         maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d]));
1287:       }
1288:     }
1289:     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1290:   }
1291:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1292:   PetscFunctionReturn(PETSC_SUCCESS);
1293: }

1295: static PetscErrorCode DMPlexCreateBoxMesh_Internal(DM dm, DMPlexShape shape, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1296: {
1297:   PetscFunctionBegin;
1298:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1299:   if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1300:   else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0]));
1301:   else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1302:   else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity));
1303:   if (!interpolate && dim > 1 && !simplex) {
1304:     DM udm;

1306:     PetscCall(DMPlexUninterpolate(dm, &udm));
1307:     PetscCall(DMPlexCopyCoordinates(dm, udm));
1308:     PetscCall(DMPlexReplace_Internal(dm, &udm));
1309:   }
1310:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
1311:   PetscFunctionReturn(PETSC_SUCCESS);
1312: }

1314: /*@C
1315:   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).

1317:   Collective

1319:   Input Parameters:
1320: + comm        - The communicator for the `DM` object
1321: . dim         - The spatial dimension
1322: . simplex     - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells
1323: . faces       - Number of faces per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1324: . lower       - The lower left corner, or NULL for (0, 0, 0)
1325: . upper       - The upper right corner, or NULL for (1, 1, 1)
1326: . periodicity - The boundary type for the X,Y,Z direction, or NULL for `DM_BOUNDARY_NONE`
1327: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

1329:   Output Parameter:
1330: . dm  - The `DM` object

1332:   Level: beginner

1334:   Note:
1335:    To customize this mesh using options, use
1336: .vb
1337:   DMCreate(comm, &dm);
1338:   DMSetType(dm, DMPLEX);
1339:   DMSetFromOptions(dm);
1340: .ve
1341: and use the options in `DMSetFromOptions()`.

1343:   Here is the numbering returned for 2 faces in each direction for tensor cells:
1344: .vb
1345:  10---17---11---18----12
1346:   |         |         |
1347:   |         |         |
1348:  20    2   22    3    24
1349:   |         |         |
1350:   |         |         |
1351:   7---15----8---16----9
1352:   |         |         |
1353:   |         |         |
1354:  19    0   21    1   23
1355:   |         |         |
1356:   |         |         |
1357:   4---13----5---14----6
1358: .ve
1359: and for simplicial cells
1360: .vb
1361:  14----8---15----9----16
1362:   |\     5  |\      7 |
1363:   | \       | \       |
1364:  13   2    14    3    15
1365:   | 4   \   | 6   \   |
1366:   |       \ |       \ |
1367:  11----6---12----7----13
1368:   |\        |\        |
1369:   | \    1  | \     3 |
1370:  10   0    11    1    12
1371:   | 0   \   | 2   \   |
1372:   |       \ |       \ |
1373:   8----4----9----5----10
1374: .ve

1376: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
1377: @*/
1378: PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm)
1379: {
1380:   PetscInt       fac[3] = {1, 1, 1};
1381:   PetscReal      low[3] = {0, 0, 0};
1382:   PetscReal      upp[3] = {1, 1, 1};
1383:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};

1385:   PetscFunctionBegin;
1386:   PetscCall(DMCreate(comm, dm));
1387:   PetscCall(DMSetType(*dm, DMPLEX));
1388:   PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate));
1389:   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1390:   PetscFunctionReturn(PETSC_SUCCESS);
1391: }

1393: static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1394: {
1395:   DM       bdm, vol;
1396:   PetscInt i;

1398:   PetscFunctionBegin;
1399:   for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported");
1400:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm));
1401:   PetscCall(DMSetType(bdm, DMPLEX));
1402:   PetscCall(DMSetDimension(bdm, 2));
1403:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
1404:   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
1405:   PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, NULL, NULL, &vol));
1406:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
1407:   PetscCall(DMDestroy(&bdm));
1408:   PetscCall(DMPlexReplace_Internal(dm, &vol));
1409:   if (lower[2] != 0.0) {
1410:     Vec          v;
1411:     PetscScalar *x;
1412:     PetscInt     cDim, n;

1414:     PetscCall(DMGetCoordinatesLocal(dm, &v));
1415:     PetscCall(VecGetBlockSize(v, &cDim));
1416:     PetscCall(VecGetLocalSize(v, &n));
1417:     PetscCall(VecGetArray(v, &x));
1418:     x += cDim;
1419:     for (i = 0; i < n; i += cDim) x[i] += lower[2];
1420:     PetscCall(VecRestoreArray(v, &x));
1421:     PetscCall(DMSetCoordinatesLocal(dm, v));
1422:   }
1423:   PetscFunctionReturn(PETSC_SUCCESS);
1424: }

1426: /*@
1427:   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tesselating the (x,y) plane and extruding in the third direction using wedge cells.

1429:   Collective

1431:   Input Parameters:
1432: + comm        - The communicator for the `DM` object
1433: . faces       - Number of faces per dimension, or NULL for (1, 1, 1)
1434: . lower       - The lower left corner, or NULL for (0, 0, 0)
1435: . upper       - The upper right corner, or NULL for (1, 1, 1)
1436: . periodicity - The boundary type for the X,Y,Z direction, or NULL for `DM_BOUNDARY_NONE`
1437: . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1438: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

1440:   Output Parameter:
1441: . dm  - The `DM` object

1443:   Level: beginner

1445: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
1446: @*/
1447: PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
1448: {
1449:   PetscInt       fac[3] = {1, 1, 1};
1450:   PetscReal      low[3] = {0, 0, 0};
1451:   PetscReal      upp[3] = {1, 1, 1};
1452:   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};

1454:   PetscFunctionBegin;
1455:   PetscCall(DMCreate(comm, dm));
1456:   PetscCall(DMSetType(*dm, DMPLEX));
1457:   PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt));
1458:   if (!interpolate) {
1459:     DM udm;

1461:     PetscCall(DMPlexUninterpolate(*dm, &udm));
1462:     PetscCall(DMPlexReplace_Internal(*dm, &udm));
1463:   }
1464:   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1465:   PetscFunctionReturn(PETSC_SUCCESS);
1466: }

1468: /*
1469:   DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension.
1470:                                            Ordering is lexicographic with lowest index as least significant in ordering.
1471:                                            e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.

1473:   Input Parameters:
1474: + len - The length of the tuple
1475: . max - The maximum for each dimension, so values are in [0, max)
1476: - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition

1478:   Output Parameter:
1479: . tup - A tuple of len integers whose entries are at most 'max'

1481:   Level: developer

1483: .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal()
1484: */
1485: static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[])
1486: {
1487:   PetscInt i;

1489:   PetscFunctionBegin;
1490:   for (i = 0; i < len; ++i) {
1491:     if (tup[i] < max[i] - 1) {
1492:       break;
1493:     } else {
1494:       tup[i] = 0;
1495:     }
1496:   }
1497:   if (i == len) tup[i - 1] = max[i - 1];
1498:   else ++tup[i];
1499:   PetscFunctionReturn(PETSC_SUCCESS);
1500: }

1502: static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[])
1503: {
1504:   PetscInt i, idx = tup[len - 1];

1506:   for (i = len - 2; i >= 0; --i) {
1507:     idx *= max[i];
1508:     idx += tup[i];
1509:   }
1510:   return idx;
1511: }

1513: static PetscErrorCode DestroyExtent_Private(void *extent)
1514: {
1515:   return PetscFree(extent);
1516: }

1518: static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[])
1519: {
1520:   Vec          coordinates;
1521:   PetscSection coordSection;
1522:   DMLabel      cutLabel    = NULL;
1523:   PetscBool    cutMarker   = PETSC_FALSE;
1524:   PetscBool    periodic    = PETSC_FALSE;
1525:   PetscInt     numCells    = 1, c;
1526:   PetscInt     numVertices = 1, v;
1527:   PetscScalar *coords;
1528:   PetscInt    *vertices, *vert, *vtmp, *supp, cone[2];
1529:   PetscInt     d, e, cell = 0, coordSize;
1530:   PetscMPIInt  rank;

1532:   PetscFunctionBegin;
1533:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1534:   PetscCall(DMSetDimension(dm, dim));
1535:   PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp));
1536:   PetscCall(DMCreateLabel(dm, "marker"));
1537:   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
1538:   for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE;
1539:   if (periodic && cutMarker) {
1540:     PetscCall(DMCreateLabel(dm, "periodic_cut"));
1541:     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1542:   }
1543:   for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now");
1544:   for (d = 0; d < dim; ++d) {
1545:     vertices[d] = edges[d];
1546:     numVertices *= vertices[d];
1547:   }
1548:   numCells = numVertices * dim;
1549:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1550:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2));
1551:   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim));
1552:   /* TODO Loop over boundary and reset support sizes */
1553:   PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */
1554:   /* Build cell cones and vertex supports */
1555:   PetscCall(DMCreateLabel(dm, "celltype"));
1556:   while (vert[dim - 1] < vertices[dim - 1]) {
1557:     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells;
1558:     PetscInt       s      = 0;

1560:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1561:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1562:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1563:     PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT));
1564:     for (d = 0; d < dim; ++d) {
1565:       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1566:       vtmp[d] = (vert[d] + 1) % vertices[d];
1567:       cone[0] = vertex;
1568:       cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells;
1569:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Vertex %" PetscInt_FMT ":", cone[1]));
1570:       for (e = 0; e < dim; ++e) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e]));
1571:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1572:       PetscCall(DMPlexSetCone(dm, cell, cone));
1573:       PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT));
1574:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]));
1575:       ++cell;
1576:     }
1577:     for (d = 0; d < dim; ++d) {
1578:       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1579:       vtmp[d]   = (vert[d] + vertices[d] - 1) % vertices[d];
1580:       supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d;
1581:       supp[s++] = (vertex - numCells) * dim + d;
1582:       PetscCall(DMPlexSetSupport(dm, vertex, supp));
1583:     }
1584:     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1585:   }
1586:   PetscCall(DMPlexStratify(dm));
1587:   /* Build coordinates */
1588:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
1589:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
1590:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1591:   PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
1592:   for (v = numCells; v < numCells + numVertices; ++v) {
1593:     PetscCall(PetscSectionSetDof(coordSection, v, dim));
1594:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1595:   }
1596:   PetscCall(PetscSectionSetUp(coordSection));
1597:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1598:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1599:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1600:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1601:   PetscCall(VecSetBlockSize(coordinates, dim));
1602:   PetscCall(VecSetType(coordinates, VECSTANDARD));
1603:   PetscCall(VecGetArray(coordinates, &coords));
1604:   for (d = 0; d < dim; ++d) vert[d] = 0;
1605:   while (vert[dim - 1] < vertices[dim - 1]) {
1606:     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert);

1608:     for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d];
1609:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1610:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1611:     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d])));
1612:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1613:     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1614:   }
1615:   PetscCall(VecRestoreArray(coordinates, &coords));
1616:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1617:   PetscCall(VecDestroy(&coordinates));
1618:   PetscCall(PetscFree4(vertices, vert, vtmp, supp));
1619:   //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper));
1620:   // Attach the extent
1621:   {
1622:     PetscContainer c;
1623:     PetscInt      *extent;

1625:     PetscCall(PetscMalloc1(dim, &extent));
1626:     for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d];
1627:     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1628:     PetscCall(PetscContainerSetUserDestroy(c, DestroyExtent_Private));
1629:     PetscCall(PetscContainerSetPointer(c, extent));
1630:     PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c));
1631:     PetscCall(PetscContainerDestroy(&c));
1632:   }
1633:   PetscFunctionReturn(PETSC_SUCCESS);
1634: }

1636: /*@C
1637:   DMPlexCreateHypercubicMesh - Creates a peridoic mesh on the tensor product of unit intervals using only vertices and edges.

1639:   Collective

1641:   Input Parameters:
1642: + comm        - The communicator for the DM object
1643: . dim         - The spatial dimension
1644: . edges       - Number of edges per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1645: . lower       - The lower left corner, or NULL for (0, 0, 0)
1646: - upper       - The upper right corner, or NULL for (1, 1, 1)

1648:   Output Parameter:
1649: . dm  - The DM object

1651:   Note: If you want to customize this mesh using options, you just need to
1652: $  DMCreate(comm, &dm);
1653: $  DMSetType(dm, DMPLEX);
1654: $  DMSetFromOptions(dm);
1655: and use the options on the DMSetFromOptions() page.

1657:   The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively,
1658: $ 18--0-19--2-20--4-18
1659: $  |     |     |     |
1660: $ 13    15    17    13
1661: $  |     |     |     |
1662: $ 24-12-25-14-26-16-24
1663: $  |     |     |     |
1664: $  7     9    11     7
1665: $  |     |     |     |
1666: $ 21--6-22--8-23-10-21
1667: $  |     |     |     |
1668: $  1     3     5     1
1669: $  |     |     |     |
1670: $ 18--0-19--2-20--4-18

1672:   Level: beginner

1674: .seealso: DMSetFromOptions(), DMPlexCreateFromFile(), DMPlexCreateHexCylinderMesh(), DMSetType(), DMCreate()
1675: @*/
1676: PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm)
1677: {
1678:   PetscInt       *edg;
1679:   PetscReal      *low, *upp;
1680:   DMBoundaryType *bdt;
1681:   PetscInt        d;

1683:   PetscFunctionBegin;
1684:   PetscCall(DMCreate(comm, dm));
1685:   PetscCall(DMSetType(*dm, DMPLEX));
1686:   PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt));
1687:   for (d = 0; d < dim; ++d) {
1688:     edg[d] = edges ? edges[d] : 1;
1689:     low[d] = lower ? lower[d] : 0.;
1690:     upp[d] = upper ? upper[d] : 1.;
1691:     bdt[d] = DM_BOUNDARY_PERIODIC;
1692:   }
1693:   PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt));
1694:   PetscCall(PetscFree4(edg, low, upp, bdt));
1695:   PetscFunctionReturn(PETSC_SUCCESS);
1696: }

1698: /*@C
1699:   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database.

1701:   Logically Collective on dm

1703:   Input Parameters:
1704: + dm - the DM context
1705: - prefix - the prefix to prepend to all option names

1707:   Level: advanced

1709:   Note:
1710:   A hyphen (-) must NOT be given at the beginning of the prefix name.
1711:   The first character of all runtime options is AUTOMATICALLY the hyphen.

1713: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()`
1714: @*/
1715: PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1716: {
1717:   DM_Plex *mesh = (DM_Plex *)dm->data;

1719:   PetscFunctionBegin;
1721:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
1722:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix));
1723:   PetscFunctionReturn(PETSC_SUCCESS);
1724: }

1726: /* Remap geometry to cylinder
1727:    TODO: This only works for a single refinement, then it is broken

1729:      Interior square: Linear interpolation is correct
1730:      The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1731:      such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance

1733:        phi     = arctan(y/x)
1734:        d_close = sqrt(1/8 + 1/4 sin^2(phi))
1735:        d_far   = sqrt(1/2 + sin^2(phi))

1737:      so we remap them using

1739:        x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1740:        y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)

1742:      If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1743: */
1744: static void snapToCylinder(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1745: {
1746:   const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
1747:   const PetscReal ds2 = 0.5 * dis;

1749:   if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) {
1750:     f0[0] = u[0];
1751:     f0[1] = u[1];
1752:   } else {
1753:     PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;

1755:     x    = PetscRealPart(u[0]);
1756:     y    = PetscRealPart(u[1]);
1757:     phi  = PetscAtan2Real(y, x);
1758:     sinp = PetscSinReal(phi);
1759:     cosp = PetscCosReal(phi);
1760:     if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) {
1761:       dc = PetscAbsReal(ds2 / sinp);
1762:       df = PetscAbsReal(dis / sinp);
1763:       xc = ds2 * x / PetscAbsReal(y);
1764:       yc = ds2 * PetscSignReal(y);
1765:     } else {
1766:       dc = PetscAbsReal(ds2 / cosp);
1767:       df = PetscAbsReal(dis / cosp);
1768:       xc = ds2 * PetscSignReal(x);
1769:       yc = ds2 * y / PetscAbsReal(x);
1770:     }
1771:     f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc);
1772:     f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc);
1773:   }
1774:   f0[2] = u[2];
1775: }

1777: static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ)
1778: {
1779:   const PetscInt dim = 3;
1780:   PetscInt       numCells, numVertices;
1781:   PetscMPIInt    rank;

1783:   PetscFunctionBegin;
1784:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1785:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1786:   PetscCall(DMSetDimension(dm, dim));
1787:   /* Create topology */
1788:   {
1789:     PetscInt cone[8], c;

1791:     numCells    = rank == 0 ? 5 : 0;
1792:     numVertices = rank == 0 ? 16 : 0;
1793:     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1794:       numCells *= 3;
1795:       numVertices = rank == 0 ? 24 : 0;
1796:     }
1797:     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1798:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8));
1799:     PetscCall(DMSetUp(dm));
1800:     if (rank == 0) {
1801:       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1802:         cone[0] = 15;
1803:         cone[1] = 18;
1804:         cone[2] = 17;
1805:         cone[3] = 16;
1806:         cone[4] = 31;
1807:         cone[5] = 32;
1808:         cone[6] = 33;
1809:         cone[7] = 34;
1810:         PetscCall(DMPlexSetCone(dm, 0, cone));
1811:         cone[0] = 16;
1812:         cone[1] = 17;
1813:         cone[2] = 24;
1814:         cone[3] = 23;
1815:         cone[4] = 32;
1816:         cone[5] = 36;
1817:         cone[6] = 37;
1818:         cone[7] = 33; /* 22 25 26 21 */
1819:         PetscCall(DMPlexSetCone(dm, 1, cone));
1820:         cone[0] = 18;
1821:         cone[1] = 27;
1822:         cone[2] = 24;
1823:         cone[3] = 17;
1824:         cone[4] = 34;
1825:         cone[5] = 33;
1826:         cone[6] = 37;
1827:         cone[7] = 38;
1828:         PetscCall(DMPlexSetCone(dm, 2, cone));
1829:         cone[0] = 29;
1830:         cone[1] = 27;
1831:         cone[2] = 18;
1832:         cone[3] = 15;
1833:         cone[4] = 35;
1834:         cone[5] = 31;
1835:         cone[6] = 34;
1836:         cone[7] = 38;
1837:         PetscCall(DMPlexSetCone(dm, 3, cone));
1838:         cone[0] = 29;
1839:         cone[1] = 15;
1840:         cone[2] = 16;
1841:         cone[3] = 23;
1842:         cone[4] = 35;
1843:         cone[5] = 36;
1844:         cone[6] = 32;
1845:         cone[7] = 31;
1846:         PetscCall(DMPlexSetCone(dm, 4, cone));

1848:         cone[0] = 31;
1849:         cone[1] = 34;
1850:         cone[2] = 33;
1851:         cone[3] = 32;
1852:         cone[4] = 19;
1853:         cone[5] = 22;
1854:         cone[6] = 21;
1855:         cone[7] = 20;
1856:         PetscCall(DMPlexSetCone(dm, 5, cone));
1857:         cone[0] = 32;
1858:         cone[1] = 33;
1859:         cone[2] = 37;
1860:         cone[3] = 36;
1861:         cone[4] = 22;
1862:         cone[5] = 25;
1863:         cone[6] = 26;
1864:         cone[7] = 21;
1865:         PetscCall(DMPlexSetCone(dm, 6, cone));
1866:         cone[0] = 34;
1867:         cone[1] = 38;
1868:         cone[2] = 37;
1869:         cone[3] = 33;
1870:         cone[4] = 20;
1871:         cone[5] = 21;
1872:         cone[6] = 26;
1873:         cone[7] = 28;
1874:         PetscCall(DMPlexSetCone(dm, 7, cone));
1875:         cone[0] = 35;
1876:         cone[1] = 38;
1877:         cone[2] = 34;
1878:         cone[3] = 31;
1879:         cone[4] = 30;
1880:         cone[5] = 19;
1881:         cone[6] = 20;
1882:         cone[7] = 28;
1883:         PetscCall(DMPlexSetCone(dm, 8, cone));
1884:         cone[0] = 35;
1885:         cone[1] = 31;
1886:         cone[2] = 32;
1887:         cone[3] = 36;
1888:         cone[4] = 30;
1889:         cone[5] = 25;
1890:         cone[6] = 22;
1891:         cone[7] = 19;
1892:         PetscCall(DMPlexSetCone(dm, 9, cone));

1894:         cone[0] = 19;
1895:         cone[1] = 20;
1896:         cone[2] = 21;
1897:         cone[3] = 22;
1898:         cone[4] = 15;
1899:         cone[5] = 16;
1900:         cone[6] = 17;
1901:         cone[7] = 18;
1902:         PetscCall(DMPlexSetCone(dm, 10, cone));
1903:         cone[0] = 22;
1904:         cone[1] = 21;
1905:         cone[2] = 26;
1906:         cone[3] = 25;
1907:         cone[4] = 16;
1908:         cone[5] = 23;
1909:         cone[6] = 24;
1910:         cone[7] = 17;
1911:         PetscCall(DMPlexSetCone(dm, 11, cone));
1912:         cone[0] = 20;
1913:         cone[1] = 28;
1914:         cone[2] = 26;
1915:         cone[3] = 21;
1916:         cone[4] = 18;
1917:         cone[5] = 17;
1918:         cone[6] = 24;
1919:         cone[7] = 27;
1920:         PetscCall(DMPlexSetCone(dm, 12, cone));
1921:         cone[0] = 30;
1922:         cone[1] = 28;
1923:         cone[2] = 20;
1924:         cone[3] = 19;
1925:         cone[4] = 29;
1926:         cone[5] = 15;
1927:         cone[6] = 18;
1928:         cone[7] = 27;
1929:         PetscCall(DMPlexSetCone(dm, 13, cone));
1930:         cone[0] = 30;
1931:         cone[1] = 19;
1932:         cone[2] = 22;
1933:         cone[3] = 25;
1934:         cone[4] = 29;
1935:         cone[5] = 23;
1936:         cone[6] = 16;
1937:         cone[7] = 15;
1938:         PetscCall(DMPlexSetCone(dm, 14, cone));
1939:       } else {
1940:         cone[0] = 5;
1941:         cone[1] = 8;
1942:         cone[2] = 7;
1943:         cone[3] = 6;
1944:         cone[4] = 9;
1945:         cone[5] = 12;
1946:         cone[6] = 11;
1947:         cone[7] = 10;
1948:         PetscCall(DMPlexSetCone(dm, 0, cone));
1949:         cone[0] = 6;
1950:         cone[1] = 7;
1951:         cone[2] = 14;
1952:         cone[3] = 13;
1953:         cone[4] = 12;
1954:         cone[5] = 15;
1955:         cone[6] = 16;
1956:         cone[7] = 11;
1957:         PetscCall(DMPlexSetCone(dm, 1, cone));
1958:         cone[0] = 8;
1959:         cone[1] = 17;
1960:         cone[2] = 14;
1961:         cone[3] = 7;
1962:         cone[4] = 10;
1963:         cone[5] = 11;
1964:         cone[6] = 16;
1965:         cone[7] = 18;
1966:         PetscCall(DMPlexSetCone(dm, 2, cone));
1967:         cone[0] = 19;
1968:         cone[1] = 17;
1969:         cone[2] = 8;
1970:         cone[3] = 5;
1971:         cone[4] = 20;
1972:         cone[5] = 9;
1973:         cone[6] = 10;
1974:         cone[7] = 18;
1975:         PetscCall(DMPlexSetCone(dm, 3, cone));
1976:         cone[0] = 19;
1977:         cone[1] = 5;
1978:         cone[2] = 6;
1979:         cone[3] = 13;
1980:         cone[4] = 20;
1981:         cone[5] = 15;
1982:         cone[6] = 12;
1983:         cone[7] = 9;
1984:         PetscCall(DMPlexSetCone(dm, 4, cone));
1985:       }
1986:     }
1987:     PetscCall(DMPlexSymmetrize(dm));
1988:     PetscCall(DMPlexStratify(dm));
1989:   }
1990:   /* Create cube geometry */
1991:   {
1992:     Vec             coordinates;
1993:     PetscSection    coordSection;
1994:     PetscScalar    *coords;
1995:     PetscInt        coordSize, v;
1996:     const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
1997:     const PetscReal ds2 = dis / 2.0;

1999:     /* Build coordinates */
2000:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2001:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2002:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2003:     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2004:     for (v = numCells; v < numCells + numVertices; ++v) {
2005:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2006:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2007:     }
2008:     PetscCall(PetscSectionSetUp(coordSection));
2009:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2010:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2011:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2012:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2013:     PetscCall(VecSetBlockSize(coordinates, dim));
2014:     PetscCall(VecSetType(coordinates, VECSTANDARD));
2015:     PetscCall(VecGetArray(coordinates, &coords));
2016:     if (rank == 0) {
2017:       coords[0 * dim + 0]  = -ds2;
2018:       coords[0 * dim + 1]  = -ds2;
2019:       coords[0 * dim + 2]  = 0.0;
2020:       coords[1 * dim + 0]  = ds2;
2021:       coords[1 * dim + 1]  = -ds2;
2022:       coords[1 * dim + 2]  = 0.0;
2023:       coords[2 * dim + 0]  = ds2;
2024:       coords[2 * dim + 1]  = ds2;
2025:       coords[2 * dim + 2]  = 0.0;
2026:       coords[3 * dim + 0]  = -ds2;
2027:       coords[3 * dim + 1]  = ds2;
2028:       coords[3 * dim + 2]  = 0.0;
2029:       coords[4 * dim + 0]  = -ds2;
2030:       coords[4 * dim + 1]  = -ds2;
2031:       coords[4 * dim + 2]  = 1.0;
2032:       coords[5 * dim + 0]  = -ds2;
2033:       coords[5 * dim + 1]  = ds2;
2034:       coords[5 * dim + 2]  = 1.0;
2035:       coords[6 * dim + 0]  = ds2;
2036:       coords[6 * dim + 1]  = ds2;
2037:       coords[6 * dim + 2]  = 1.0;
2038:       coords[7 * dim + 0]  = ds2;
2039:       coords[7 * dim + 1]  = -ds2;
2040:       coords[7 * dim + 2]  = 1.0;
2041:       coords[8 * dim + 0]  = dis;
2042:       coords[8 * dim + 1]  = -dis;
2043:       coords[8 * dim + 2]  = 0.0;
2044:       coords[9 * dim + 0]  = dis;
2045:       coords[9 * dim + 1]  = dis;
2046:       coords[9 * dim + 2]  = 0.0;
2047:       coords[10 * dim + 0] = dis;
2048:       coords[10 * dim + 1] = -dis;
2049:       coords[10 * dim + 2] = 1.0;
2050:       coords[11 * dim + 0] = dis;
2051:       coords[11 * dim + 1] = dis;
2052:       coords[11 * dim + 2] = 1.0;
2053:       coords[12 * dim + 0] = -dis;
2054:       coords[12 * dim + 1] = dis;
2055:       coords[12 * dim + 2] = 0.0;
2056:       coords[13 * dim + 0] = -dis;
2057:       coords[13 * dim + 1] = dis;
2058:       coords[13 * dim + 2] = 1.0;
2059:       coords[14 * dim + 0] = -dis;
2060:       coords[14 * dim + 1] = -dis;
2061:       coords[14 * dim + 2] = 0.0;
2062:       coords[15 * dim + 0] = -dis;
2063:       coords[15 * dim + 1] = -dis;
2064:       coords[15 * dim + 2] = 1.0;
2065:       if (periodicZ == DM_BOUNDARY_PERIODIC) {
2066:         /* 15 31 19 */ coords[16 * dim + 0] = -ds2;
2067:         coords[16 * dim + 1]                = -ds2;
2068:         coords[16 * dim + 2]                = 0.5;
2069:         /* 16 32 22 */ coords[17 * dim + 0] = ds2;
2070:         coords[17 * dim + 1]                = -ds2;
2071:         coords[17 * dim + 2]                = 0.5;
2072:         /* 17 33 21 */ coords[18 * dim + 0] = ds2;
2073:         coords[18 * dim + 1]                = ds2;
2074:         coords[18 * dim + 2]                = 0.5;
2075:         /* 18 34 20 */ coords[19 * dim + 0] = -ds2;
2076:         coords[19 * dim + 1]                = ds2;
2077:         coords[19 * dim + 2]                = 0.5;
2078:         /* 29 35 30 */ coords[20 * dim + 0] = -dis;
2079:         coords[20 * dim + 1]                = -dis;
2080:         coords[20 * dim + 2]                = 0.5;
2081:         /* 23 36 25 */ coords[21 * dim + 0] = dis;
2082:         coords[21 * dim + 1]                = -dis;
2083:         coords[21 * dim + 2]                = 0.5;
2084:         /* 24 37 26 */ coords[22 * dim + 0] = dis;
2085:         coords[22 * dim + 1]                = dis;
2086:         coords[22 * dim + 2]                = 0.5;
2087:         /* 27 38 28 */ coords[23 * dim + 0] = -dis;
2088:         coords[23 * dim + 1]                = dis;
2089:         coords[23 * dim + 2]                = 0.5;
2090:       }
2091:     }
2092:     PetscCall(VecRestoreArray(coordinates, &coords));
2093:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2094:     PetscCall(VecDestroy(&coordinates));
2095:   }
2096:   /* Create periodicity */
2097:   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
2098:     PetscReal L[3]       = {-1., -1., 0.};
2099:     PetscReal maxCell[3] = {-1., -1., 0.};
2100:     PetscReal lower[3]   = {0.0, 0.0, 0.0};
2101:     PetscReal upper[3]   = {1.0, 1.0, 1.5};
2102:     PetscInt  numZCells  = 3;

2104:     L[2]       = upper[2] - lower[2];
2105:     maxCell[2] = 1.1 * (L[2] / numZCells);
2106:     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
2107:   }
2108:   {
2109:     DM          cdm;
2110:     PetscDS     cds;
2111:     PetscScalar c[2] = {1.0, 1.0};

2113:     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, snapToCylinder));
2114:     PetscCall(DMGetCoordinateDM(dm, &cdm));
2115:     PetscCall(DMGetDS(cdm, &cds));
2116:     PetscCall(PetscDSSetConstants(cds, 2, c));
2117:   }
2118:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));

2120:   /* Wait for coordinate creation before doing in-place modification */
2121:   PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2122:   PetscFunctionReturn(PETSC_SUCCESS);
2123: }

2125: /*@
2126:   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.

2128:   Collective

2130:   Input Parameters:
2131: + comm      - The communicator for the `DM` object
2132: - periodicZ - The boundary type for the Z direction

2134:   Output Parameter:
2135: . dm  - The DM object

2137:   Level: beginner

2139:   Note:
2140:   Here is the output numbering looking from the bottom of the cylinder:
2141: .vb
2142:        17-----14
2143:         |     |
2144:         |  2  |
2145:         |     |
2146:  17-----8-----7-----14
2147:   |     |     |     |
2148:   |  3  |  0  |  1  |
2149:   |     |     |     |
2150:  19-----5-----6-----13
2151:         |     |
2152:         |  4  |
2153:         |     |
2154:        19-----13

2156:  and up through the top

2158:        18-----16
2159:         |     |
2160:         |  2  |
2161:         |     |
2162:  18----10----11-----16
2163:   |     |     |     |
2164:   |  3  |  0  |  1  |
2165:   |     |     |     |
2166:  20-----9----12-----15
2167:         |     |
2168:         |  4  |
2169:         |     |
2170:        20-----15
2171: .ve

2173: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2174: @*/
2175: PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, DM *dm)
2176: {
2177:   PetscFunctionBegin;
2179:   PetscCall(DMCreate(comm, dm));
2180:   PetscCall(DMSetType(*dm, DMPLEX));
2181:   PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ));
2182:   PetscFunctionReturn(PETSC_SUCCESS);
2183: }

2185: static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate)
2186: {
2187:   const PetscInt dim = 3;
2188:   PetscInt       numCells, numVertices, v;
2189:   PetscMPIInt    rank;

2191:   PetscFunctionBegin;
2192:   PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n);
2193:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2194:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2195:   PetscCall(DMSetDimension(dm, dim));
2196:   /* Must create the celltype label here so that we do not automatically try to compute the types */
2197:   PetscCall(DMCreateLabel(dm, "celltype"));
2198:   /* Create topology */
2199:   {
2200:     PetscInt cone[6], c;

2202:     numCells    = rank == 0 ? n : 0;
2203:     numVertices = rank == 0 ? 2 * (n + 1) : 0;
2204:     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
2205:     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
2206:     PetscCall(DMSetUp(dm));
2207:     for (c = 0; c < numCells; c++) {
2208:       cone[0] = c + n * 1;
2209:       cone[1] = (c + 1) % n + n * 1;
2210:       cone[2] = 0 + 3 * n;
2211:       cone[3] = c + n * 2;
2212:       cone[4] = (c + 1) % n + n * 2;
2213:       cone[5] = 1 + 3 * n;
2214:       PetscCall(DMPlexSetCone(dm, c, cone));
2215:       PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR));
2216:     }
2217:     PetscCall(DMPlexSymmetrize(dm));
2218:     PetscCall(DMPlexStratify(dm));
2219:   }
2220:   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT));
2221:   /* Create cylinder geometry */
2222:   {
2223:     Vec          coordinates;
2224:     PetscSection coordSection;
2225:     PetscScalar *coords;
2226:     PetscInt     coordSize, c;

2228:     /* Build coordinates */
2229:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2230:     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2231:     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2232:     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2233:     for (v = numCells; v < numCells + numVertices; ++v) {
2234:       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2235:       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2236:     }
2237:     PetscCall(PetscSectionSetUp(coordSection));
2238:     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2239:     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2240:     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2241:     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2242:     PetscCall(VecSetBlockSize(coordinates, dim));
2243:     PetscCall(VecSetType(coordinates, VECSTANDARD));
2244:     PetscCall(VecGetArray(coordinates, &coords));
2245:     for (c = 0; c < numCells; c++) {
2246:       coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2247:       coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2248:       coords[(c + 0 * n) * dim + 2] = 1.0;
2249:       coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2250:       coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2251:       coords[(c + 1 * n) * dim + 2] = 0.0;
2252:     }
2253:     if (rank == 0) {
2254:       coords[(2 * n + 0) * dim + 0] = 0.0;
2255:       coords[(2 * n + 0) * dim + 1] = 0.0;
2256:       coords[(2 * n + 0) * dim + 2] = 1.0;
2257:       coords[(2 * n + 1) * dim + 0] = 0.0;
2258:       coords[(2 * n + 1) * dim + 1] = 0.0;
2259:       coords[(2 * n + 1) * dim + 2] = 0.0;
2260:     }
2261:     PetscCall(VecRestoreArray(coordinates, &coords));
2262:     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2263:     PetscCall(VecDestroy(&coordinates));
2264:   }
2265:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2266:   /* Interpolate */
2267:   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2268:   PetscFunctionReturn(PETSC_SUCCESS);
2269: }

2271: /*@
2272:   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.

2274:   Collective

2276:   Input Parameters:
2277: + comm - The communicator for the `DM` object
2278: . n    - The number of wedges around the origin
2279: - interpolate - Create edges and faces

2281:   Output Parameter:
2282: . dm  - The `DM` object

2284:   Level: beginner

2286: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2287: @*/
2288: PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
2289: {
2290:   PetscFunctionBegin;
2292:   PetscCall(DMCreate(comm, dm));
2293:   PetscCall(DMSetType(*dm, DMPLEX));
2294:   PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate));
2295:   PetscFunctionReturn(PETSC_SUCCESS);
2296: }

2298: static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2299: {
2300:   PetscReal prod = 0.0;
2301:   PetscInt  i;
2302:   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
2303:   return PetscSqrtReal(prod);
2304: }
2305: static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2306: {
2307:   PetscReal prod = 0.0;
2308:   PetscInt  i;
2309:   for (i = 0; i < dim; ++i) prod += x[i] * y[i];
2310:   return prod;
2311: }

2313: /* The first constant is the sphere radius */
2314: static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
2315: {
2316:   PetscReal r     = PetscRealPart(constants[0]);
2317:   PetscReal norm2 = 0.0, fac;
2318:   PetscInt  n     = uOff[1] - uOff[0], d;

2320:   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
2321:   fac = r / PetscSqrtReal(norm2);
2322:   for (d = 0; d < n; ++d) f0[d] = u[d] * fac;
2323: }

2325: static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R)
2326: {
2327:   const PetscInt embedDim = dim + 1;
2328:   PetscSection   coordSection;
2329:   Vec            coordinates;
2330:   PetscScalar   *coords;
2331:   PetscReal     *coordsIn;
2332:   PetscInt       numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, c, e;
2333:   PetscMPIInt    rank;

2335:   PetscFunctionBegin;
2337:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2338:   PetscCall(DMSetDimension(dm, dim));
2339:   PetscCall(DMSetCoordinateDim(dm, dim + 1));
2340:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2341:   switch (dim) {
2342:   case 2:
2343:     if (simplex) {
2344:       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI);
2345:       const PetscReal edgeLen   = 2.0 / (1.0 + PETSC_PHI) * (R / radius);
2346:       const PetscInt  degree    = 5;
2347:       PetscReal       vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)};
2348:       PetscInt        s[3]      = {1, 1, 1};
2349:       PetscInt        cone[3];
2350:       PetscInt       *graph, p, i, j, k;

2352:       vertex[0] *= R / radius;
2353:       vertex[1] *= R / radius;
2354:       vertex[2] *= R / radius;
2355:       numCells    = rank == 0 ? 20 : 0;
2356:       numVerts    = rank == 0 ? 12 : 0;
2357:       firstVertex = numCells;
2358:       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of

2360:            (0, \pm 1/\phi+1, \pm \phi/\phi+1)

2362:          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2363:          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
2364:       */
2365:       /* Construct vertices */
2366:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2367:       if (rank == 0) {
2368:         for (p = 0, i = 0; p < embedDim; ++p) {
2369:           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2370:             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2371:               for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim];
2372:               ++i;
2373:             }
2374:           }
2375:         }
2376:       }
2377:       /* Construct graph */
2378:       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2379:       for (i = 0; i < numVerts; ++i) {
2380:         for (j = 0, k = 0; j < numVerts; ++j) {
2381:           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2382:             graph[i * numVerts + j] = 1;
2383:             ++k;
2384:           }
2385:         }
2386:         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2387:       }
2388:       /* Build Topology */
2389:       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2390:       for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2391:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2392:       /* Cells */
2393:       for (i = 0, c = 0; i < numVerts; ++i) {
2394:         for (j = 0; j < i; ++j) {
2395:           for (k = 0; k < j; ++k) {
2396:             if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) {
2397:               cone[0] = firstVertex + i;
2398:               cone[1] = firstVertex + j;
2399:               cone[2] = firstVertex + k;
2400:               /* Check orientation */
2401:               {
2402:                 const PetscInt epsilon[3][3][3] = {
2403:                   {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
2404:                   {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
2405:                   {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
2406:                 };
2407:                 PetscReal normal[3];
2408:                 PetscInt  e, f;

2410:                 for (d = 0; d < embedDim; ++d) {
2411:                   normal[d] = 0.0;
2412:                   for (e = 0; e < embedDim; ++e) {
2413:                     for (f = 0; f < embedDim; ++f) normal[d] += epsilon[d][e][f] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]);
2414:                   }
2415:                 }
2416:                 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2417:                   PetscInt tmp = cone[1];
2418:                   cone[1]      = cone[2];
2419:                   cone[2]      = tmp;
2420:                 }
2421:               }
2422:               PetscCall(DMPlexSetCone(dm, c++, cone));
2423:             }
2424:           }
2425:         }
2426:       }
2427:       PetscCall(DMPlexSymmetrize(dm));
2428:       PetscCall(DMPlexStratify(dm));
2429:       PetscCall(PetscFree(graph));
2430:     } else {
2431:       /*
2432:         12-21--13
2433:          |     |
2434:         25  4  24
2435:          |     |
2436:   12-25--9-16--8-24--13
2437:    |     |     |     |
2438:   23  5 17  0 15  3  22
2439:    |     |     |     |
2440:   10-20--6-14--7-19--11
2441:          |     |
2442:         20  1  19
2443:          |     |
2444:         10-18--11
2445:          |     |
2446:         23  2  22
2447:          |     |
2448:         12-21--13
2449:        */
2450:       PetscInt cone[4], ornt[4];

2452:       numCells    = rank == 0 ? 6 : 0;
2453:       numEdges    = rank == 0 ? 12 : 0;
2454:       numVerts    = rank == 0 ? 8 : 0;
2455:       firstVertex = numCells;
2456:       firstEdge   = numCells + numVerts;
2457:       /* Build Topology */
2458:       PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts));
2459:       for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4));
2460:       for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
2461:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2462:       if (rank == 0) {
2463:         /* Cell 0 */
2464:         cone[0] = 14;
2465:         cone[1] = 15;
2466:         cone[2] = 16;
2467:         cone[3] = 17;
2468:         PetscCall(DMPlexSetCone(dm, 0, cone));
2469:         ornt[0] = 0;
2470:         ornt[1] = 0;
2471:         ornt[2] = 0;
2472:         ornt[3] = 0;
2473:         PetscCall(DMPlexSetConeOrientation(dm, 0, ornt));
2474:         /* Cell 1 */
2475:         cone[0] = 18;
2476:         cone[1] = 19;
2477:         cone[2] = 14;
2478:         cone[3] = 20;
2479:         PetscCall(DMPlexSetCone(dm, 1, cone));
2480:         ornt[0] = 0;
2481:         ornt[1] = 0;
2482:         ornt[2] = -1;
2483:         ornt[3] = 0;
2484:         PetscCall(DMPlexSetConeOrientation(dm, 1, ornt));
2485:         /* Cell 2 */
2486:         cone[0] = 21;
2487:         cone[1] = 22;
2488:         cone[2] = 18;
2489:         cone[3] = 23;
2490:         PetscCall(DMPlexSetCone(dm, 2, cone));
2491:         ornt[0] = 0;
2492:         ornt[1] = 0;
2493:         ornt[2] = -1;
2494:         ornt[3] = 0;
2495:         PetscCall(DMPlexSetConeOrientation(dm, 2, ornt));
2496:         /* Cell 3 */
2497:         cone[0] = 19;
2498:         cone[1] = 22;
2499:         cone[2] = 24;
2500:         cone[3] = 15;
2501:         PetscCall(DMPlexSetCone(dm, 3, cone));
2502:         ornt[0] = -1;
2503:         ornt[1] = -1;
2504:         ornt[2] = 0;
2505:         ornt[3] = -1;
2506:         PetscCall(DMPlexSetConeOrientation(dm, 3, ornt));
2507:         /* Cell 4 */
2508:         cone[0] = 16;
2509:         cone[1] = 24;
2510:         cone[2] = 21;
2511:         cone[3] = 25;
2512:         PetscCall(DMPlexSetCone(dm, 4, cone));
2513:         ornt[0] = -1;
2514:         ornt[1] = -1;
2515:         ornt[2] = -1;
2516:         ornt[3] = 0;
2517:         PetscCall(DMPlexSetConeOrientation(dm, 4, ornt));
2518:         /* Cell 5 */
2519:         cone[0] = 20;
2520:         cone[1] = 17;
2521:         cone[2] = 25;
2522:         cone[3] = 23;
2523:         PetscCall(DMPlexSetCone(dm, 5, cone));
2524:         ornt[0] = -1;
2525:         ornt[1] = -1;
2526:         ornt[2] = -1;
2527:         ornt[3] = -1;
2528:         PetscCall(DMPlexSetConeOrientation(dm, 5, ornt));
2529:         /* Edges */
2530:         cone[0] = 6;
2531:         cone[1] = 7;
2532:         PetscCall(DMPlexSetCone(dm, 14, cone));
2533:         cone[0] = 7;
2534:         cone[1] = 8;
2535:         PetscCall(DMPlexSetCone(dm, 15, cone));
2536:         cone[0] = 8;
2537:         cone[1] = 9;
2538:         PetscCall(DMPlexSetCone(dm, 16, cone));
2539:         cone[0] = 9;
2540:         cone[1] = 6;
2541:         PetscCall(DMPlexSetCone(dm, 17, cone));
2542:         cone[0] = 10;
2543:         cone[1] = 11;
2544:         PetscCall(DMPlexSetCone(dm, 18, cone));
2545:         cone[0] = 11;
2546:         cone[1] = 7;
2547:         PetscCall(DMPlexSetCone(dm, 19, cone));
2548:         cone[0] = 6;
2549:         cone[1] = 10;
2550:         PetscCall(DMPlexSetCone(dm, 20, cone));
2551:         cone[0] = 12;
2552:         cone[1] = 13;
2553:         PetscCall(DMPlexSetCone(dm, 21, cone));
2554:         cone[0] = 13;
2555:         cone[1] = 11;
2556:         PetscCall(DMPlexSetCone(dm, 22, cone));
2557:         cone[0] = 10;
2558:         cone[1] = 12;
2559:         PetscCall(DMPlexSetCone(dm, 23, cone));
2560:         cone[0] = 13;
2561:         cone[1] = 8;
2562:         PetscCall(DMPlexSetCone(dm, 24, cone));
2563:         cone[0] = 12;
2564:         cone[1] = 9;
2565:         PetscCall(DMPlexSetCone(dm, 25, cone));
2566:       }
2567:       PetscCall(DMPlexSymmetrize(dm));
2568:       PetscCall(DMPlexStratify(dm));
2569:       /* Build coordinates */
2570:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2571:       if (rank == 0) {
2572:         coordsIn[0 * embedDim + 0] = -R;
2573:         coordsIn[0 * embedDim + 1] = R;
2574:         coordsIn[0 * embedDim + 2] = -R;
2575:         coordsIn[1 * embedDim + 0] = R;
2576:         coordsIn[1 * embedDim + 1] = R;
2577:         coordsIn[1 * embedDim + 2] = -R;
2578:         coordsIn[2 * embedDim + 0] = R;
2579:         coordsIn[2 * embedDim + 1] = -R;
2580:         coordsIn[2 * embedDim + 2] = -R;
2581:         coordsIn[3 * embedDim + 0] = -R;
2582:         coordsIn[3 * embedDim + 1] = -R;
2583:         coordsIn[3 * embedDim + 2] = -R;
2584:         coordsIn[4 * embedDim + 0] = -R;
2585:         coordsIn[4 * embedDim + 1] = R;
2586:         coordsIn[4 * embedDim + 2] = R;
2587:         coordsIn[5 * embedDim + 0] = R;
2588:         coordsIn[5 * embedDim + 1] = R;
2589:         coordsIn[5 * embedDim + 2] = R;
2590:         coordsIn[6 * embedDim + 0] = -R;
2591:         coordsIn[6 * embedDim + 1] = -R;
2592:         coordsIn[6 * embedDim + 2] = R;
2593:         coordsIn[7 * embedDim + 0] = R;
2594:         coordsIn[7 * embedDim + 1] = -R;
2595:         coordsIn[7 * embedDim + 2] = R;
2596:       }
2597:     }
2598:     break;
2599:   case 3:
2600:     if (simplex) {
2601:       const PetscReal edgeLen         = 1.0 / PETSC_PHI;
2602:       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
2603:       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
2604:       PetscReal       vertexC[4]      = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0};
2605:       const PetscInt  degree          = 12;
2606:       PetscInt        s[4]            = {1, 1, 1};
2607:       PetscInt        evenPerm[12][4] = {
2608:         {0, 1, 2, 3},
2609:         {0, 2, 3, 1},
2610:         {0, 3, 1, 2},
2611:         {1, 0, 3, 2},
2612:         {1, 2, 0, 3},
2613:         {1, 3, 2, 0},
2614:         {2, 0, 1, 3},
2615:         {2, 1, 3, 0},
2616:         {2, 3, 0, 1},
2617:         {3, 0, 2, 1},
2618:         {3, 1, 0, 2},
2619:         {3, 2, 1, 0}
2620:       };
2621:       PetscInt  cone[4];
2622:       PetscInt *graph, p, i, j, k, l;

2624:       vertexA[0] *= R;
2625:       vertexA[1] *= R;
2626:       vertexA[2] *= R;
2627:       vertexA[3] *= R;
2628:       vertexB[0] *= R;
2629:       vertexB[1] *= R;
2630:       vertexB[2] *= R;
2631:       vertexB[3] *= R;
2632:       vertexC[0] *= R;
2633:       vertexC[1] *= R;
2634:       vertexC[2] *= R;
2635:       vertexC[3] *= R;
2636:       numCells    = rank == 0 ? 600 : 0;
2637:       numVerts    = rank == 0 ? 120 : 0;
2638:       firstVertex = numCells;
2639:       /* Use the 600-cell, which for a unit sphere has coordinates which are

2641:            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
2642:                (\pm 1,    0,       0,      0)  all cyclic permutations   8
2643:            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96

2645:          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2646:          length is then given by 1/\phi = 0.61803.

2648:          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
2649:          http://mathworld.wolfram.com/600-Cell.html
2650:       */
2651:       /* Construct vertices */
2652:       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2653:       i = 0;
2654:       if (rank == 0) {
2655:         for (s[0] = -1; s[0] < 2; s[0] += 2) {
2656:           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2657:             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2658:               for (s[3] = -1; s[3] < 2; s[3] += 2) {
2659:                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d];
2660:                 ++i;
2661:               }
2662:             }
2663:           }
2664:         }
2665:         for (p = 0; p < embedDim; ++p) {
2666:           s[1] = s[2] = s[3] = 1;
2667:           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2668:             for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim];
2669:             ++i;
2670:           }
2671:         }
2672:         for (p = 0; p < 12; ++p) {
2673:           s[3] = 1;
2674:           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2675:             for (s[1] = -1; s[1] < 2; s[1] += 2) {
2676:               for (s[2] = -1; s[2] < 2; s[2] += 2) {
2677:                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]];
2678:                 ++i;
2679:               }
2680:             }
2681:           }
2682:         }
2683:       }
2684:       PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts);
2685:       /* Construct graph */
2686:       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2687:       for (i = 0; i < numVerts; ++i) {
2688:         for (j = 0, k = 0; j < numVerts; ++j) {
2689:           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2690:             graph[i * numVerts + j] = 1;
2691:             ++k;
2692:           }
2693:         }
2694:         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2695:       }
2696:       /* Build Topology */
2697:       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2698:       for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2699:       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2700:       /* Cells */
2701:       if (rank == 0) {
2702:         for (i = 0, c = 0; i < numVerts; ++i) {
2703:           for (j = 0; j < i; ++j) {
2704:             for (k = 0; k < j; ++k) {
2705:               for (l = 0; l < k; ++l) {
2706:                 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i] && graph[l * numVerts + i] && graph[l * numVerts + j] && graph[l * numVerts + k]) {
2707:                   cone[0] = firstVertex + i;
2708:                   cone[1] = firstVertex + j;
2709:                   cone[2] = firstVertex + k;
2710:                   cone[3] = firstVertex + l;
2711:                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
2712:                   {
2713:                     const PetscInt epsilon[4][4][4][4] = {
2714:                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, -1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 0, 0}, {0, 1, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 1, 0}, {0, -1, 0, 0}, {0, 0, 0, 0}}},

2716:                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}}, {{0, 0, -1, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}}},

2718:                       {{{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}, {0, -1, 0, 0}}, {{0, 0, 0, -1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 1, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}},

2720:                       {{{0, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 1, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}}, {{0, -1, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} }
2721:                     };
2722:                     PetscReal normal[4];
2723:                     PetscInt  e, f, g;

2725:                     for (d = 0; d < embedDim; ++d) {
2726:                       normal[d] = 0.0;
2727:                       for (e = 0; e < embedDim; ++e) {
2728:                         for (f = 0; f < embedDim; ++f) {
2729:                           for (g = 0; g < embedDim; ++g) {
2730:                             normal[d] += epsilon[d][e][f][g] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]) * (coordsIn[l * embedDim + f] - coordsIn[i * embedDim + f]);
2731:                           }
2732:                         }
2733:                       }
2734:                     }
2735:                     if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2736:                       PetscInt tmp = cone[1];
2737:                       cone[1]      = cone[2];
2738:                       cone[2]      = tmp;
2739:                     }
2740:                   }
2741:                   PetscCall(DMPlexSetCone(dm, c++, cone));
2742:                 }
2743:               }
2744:             }
2745:           }
2746:         }
2747:       }
2748:       PetscCall(DMPlexSymmetrize(dm));
2749:       PetscCall(DMPlexStratify(dm));
2750:       PetscCall(PetscFree(graph));
2751:     }
2752:     break;
2753:   default:
2754:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim);
2755:   }
2756:   /* Create coordinates */
2757:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2758:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2759:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim));
2760:   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts));
2761:   for (v = firstVertex; v < firstVertex + numVerts; ++v) {
2762:     PetscCall(PetscSectionSetDof(coordSection, v, embedDim));
2763:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim));
2764:   }
2765:   PetscCall(PetscSectionSetUp(coordSection));
2766:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2767:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2768:   PetscCall(VecSetBlockSize(coordinates, embedDim));
2769:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2770:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2771:   PetscCall(VecSetType(coordinates, VECSTANDARD));
2772:   PetscCall(VecGetArray(coordinates, &coords));
2773:   for (v = 0; v < numVerts; ++v)
2774:     for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d];
2775:   PetscCall(VecRestoreArray(coordinates, &coords));
2776:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2777:   PetscCall(VecDestroy(&coordinates));
2778:   PetscCall(PetscFree(coordsIn));
2779:   {
2780:     DM          cdm;
2781:     PetscDS     cds;
2782:     PetscScalar c = R;

2784:     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, snapToSphere));
2785:     PetscCall(DMGetCoordinateDM(dm, &cdm));
2786:     PetscCall(DMGetDS(cdm, &cds));
2787:     PetscCall(PetscDSSetConstants(cds, 1, &c));
2788:   }
2789:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2790:   /* Wait for coordinate creation before doing in-place modification */
2791:   if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2792:   PetscFunctionReturn(PETSC_SUCCESS);
2793: }

2795: typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]);

2797: /*
2798:  The Schwarz P implicit surface is

2800:      f(x) = cos(x0) + cos(x1) + cos(x2) = 0
2801: */
2802: static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2803: {
2804:   PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)};
2805:   PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)};
2806:   f[0]           = c[0] + c[1] + c[2];
2807:   for (PetscInt i = 0; i < 3; i++) {
2808:     grad[i] = PETSC_PI * g[i];
2809:     for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.;
2810:   }
2811: }

2813: // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2814: static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2815: {
2816:   for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI);
2817:   return PETSC_SUCCESS;
2818: }

2820: /*
2821:  The Gyroid implicit surface is

2823:  f(x,y,z) = sin(pi * x) * cos (pi * (y + 1/2))  + sin(pi * (y + 1/2)) * cos(pi * (z + 1/4)) + sin(pi * (z + 1/4)) * cos(pi * x)

2825: */
2826: static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2827: {
2828:   PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))};
2829:   PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))};
2830:   f[0]           = s[0] * c[1] + s[1] * c[2] + s[2] * c[0];
2831:   grad[0]        = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2832:   grad[1]        = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2833:   grad[2]        = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2834:   hess[0][0]     = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]);
2835:   hess[0][1]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2836:   hess[0][2]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2837:   hess[1][0]     = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]);
2838:   hess[1][1]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2839:   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2840:   hess[2][0]     = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]);
2841:   hess[2][1]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2842:   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2843: }

2845: // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2846: static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2847: {
2848:   PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))};
2849:   PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))};
2850:   u[0]           = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2851:   u[1]           = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2852:   u[2]           = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2853:   return PETSC_SUCCESS;
2854: }

2856: /*
2857:    We wish to solve

2859:          min_y || y - x ||^2  subject to f(y) = 0

2861:    Let g(y) = grad(f).  The minimization problem is equivalent to asking to satisfy
2862:    f(y) = 0 and (y-x) is parallel to g(y).  We do this by using Householder QR to obtain a basis for the
2863:    tangent space and ask for both components in the tangent space to be zero.

2865:    Take g to be a column vector and compute the "full QR" factorization Q R = g,
2866:    where Q = I - 2 n n^T is a symmetric orthogonal matrix.
2867:    The first column of Q is parallel to g so the remaining two columns span the null space.
2868:    Let Qn = Q[:,1:] be those remaining columns.  Then Qn Qn^T is an orthogonal projector into the tangent space.
2869:    Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries.
2870:    In total, we have a system of 3 equations in 3 unknowns:

2872:      f(y) = 0                       1 equation
2873:      Qn^T (y - x) = 0               2 equations

2875:    Here, we compute the residual and Jacobian of this system.
2876: */
2877: static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[])
2878: {
2879:   PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])};
2880:   PetscReal d[3]     = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])};
2881:   PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign;
2882:   PetscReal n_y[3][3] = {
2883:     {0, 0, 0},
2884:     {0, 0, 0},
2885:     {0, 0, 0}
2886:   };

2888:   feval(yreal, &f, grad, n_y);

2890:   for (PetscInt i = 0; i < 3; i++) n[i] = grad[i];
2891:   norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2892:   for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i];

2894:   // Define the Householder reflector
2895:   sign = n[0] >= 0 ? 1. : -1.;
2896:   n[0] += norm * sign;
2897:   for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign;

2899:   norm      = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2900:   norm_y[0] = 1. / norm * (n[0] * n_y[0][0]);
2901:   norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]);
2902:   norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]);

2904:   for (PetscInt i = 0; i < 3; i++) {
2905:     n[i] /= norm;
2906:     for (PetscInt j = 0; j < 3; j++) {
2907:       // note that n[i] is n_old[i]/norm when executing the code below
2908:       n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j];
2909:     }
2910:   }

2912:   nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2];
2913:   for (PetscInt i = 0; i < 3; i++) nd_y[i] = n[i] + n_y[0][i] * d[0] + n_y[1][i] * d[1] + n_y[2][i] * d[2];

2915:   res[0] = f;
2916:   res[1] = d[1] - 2 * n[1] * nd;
2917:   res[2] = d[2] - 2 * n[2] * nd;
2918:   // J[j][i] is J_{ij} (column major)
2919:   for (PetscInt j = 0; j < 3; j++) {
2920:     J[0 + j * 3] = grad[j];
2921:     J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]);
2922:     J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]);
2923:   }
2924: }

2926: /*
2927:    Project x to the nearest point on the implicit surface using Newton's method.
2928: */
2929: static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[])
2930: {
2931:   PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess

2933:   PetscFunctionBegin;
2934:   for (PetscInt iter = 0; iter < 10; iter++) {
2935:     PetscScalar res[3], J[9];
2936:     PetscReal   resnorm;
2937:     TPSNearestPointResJac(feval, x, y, res, J);
2938:     resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2])));
2939:     if (0) { // Turn on this monitor if you need to confirm quadratic convergence
2940:       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%" PetscInt_FMT "] res [%g %g %g]\n", iter, (double)PetscRealPart(res[0]), (double)PetscRealPart(res[1]), (double)PetscRealPart(res[2])));
2941:     }
2942:     if (resnorm < PETSC_SMALL) break;

2944:     // Take the Newton step
2945:     PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL));
2946:     PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res);
2947:   }
2948:   for (PetscInt i = 0; i < 3; i++) x[i] = y[i];
2949:   PetscFunctionReturn(PETSC_SUCCESS);
2950: }

2952: const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL};

2954: static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness)
2955: {
2956:   PetscMPIInt rank;
2957:   PetscInt    topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0;
2958:   PetscInt(*edges)[2] = NULL, *edgeSets = NULL;
2959:   PetscInt            *cells_flat = NULL;
2960:   PetscReal           *vtxCoords  = NULL;
2961:   TPSEvaluateFunc      evalFunc   = NULL;
2962:   PetscSimplePointFunc normalFunc = NULL;
2963:   DMLabel              label;

2965:   PetscFunctionBegin;
2966:   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2967:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2968:   PetscCheck((layers != 0) ^ (thickness == 0.), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Layers %" PetscInt_FMT " must be nonzero iff thickness %g is nonzero", layers, (double)thickness);
2969:   switch (tpstype) {
2970:   case DMPLEX_TPS_SCHWARZ_P:
2971:     PetscCheck(!periodic || (periodic[0] == DM_BOUNDARY_NONE && periodic[1] == DM_BOUNDARY_NONE && periodic[2] == DM_BOUNDARY_NONE), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Schwarz P does not support periodic meshes");
2972:     if (rank == 0) {
2973:       PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn]
2974:       PetscInt  Njunctions = 0, Ncuts = 0, Npipes[3], vcount;
2975:       PetscReal L = 1;

2977:       Npipes[0]   = (extent[0] + 1) * extent[1] * extent[2];
2978:       Npipes[1]   = extent[0] * (extent[1] + 1) * extent[2];
2979:       Npipes[2]   = extent[0] * extent[1] * (extent[2] + 1);
2980:       Njunctions  = extent[0] * extent[1] * extent[2];
2981:       Ncuts       = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]);
2982:       numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions;
2983:       PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords));
2984:       PetscCall(PetscMalloc1(Njunctions, &cells));
2985:       PetscCall(PetscMalloc1(Ncuts * 4, &edges));
2986:       PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets));
2987:       // x-normal pipes
2988:       vcount = 0;
2989:       for (PetscInt i = 0; i < extent[0] + 1; i++) {
2990:         for (PetscInt j = 0; j < extent[1]; j++) {
2991:           for (PetscInt k = 0; k < extent[2]; k++) {
2992:             for (PetscInt l = 0; l < 4; l++) {
2993:               vtxCoords[vcount++] = (2 * i - 1) * L;
2994:               vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
2995:               vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
2996:             }
2997:           }
2998:         }
2999:       }
3000:       // y-normal pipes
3001:       for (PetscInt i = 0; i < extent[0]; i++) {
3002:         for (PetscInt j = 0; j < extent[1] + 1; j++) {
3003:           for (PetscInt k = 0; k < extent[2]; k++) {
3004:             for (PetscInt l = 0; l < 4; l++) {
3005:               vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3006:               vtxCoords[vcount++] = (2 * j - 1) * L;
3007:               vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3008:             }
3009:           }
3010:         }
3011:       }
3012:       // z-normal pipes
3013:       for (PetscInt i = 0; i < extent[0]; i++) {
3014:         for (PetscInt j = 0; j < extent[1]; j++) {
3015:           for (PetscInt k = 0; k < extent[2] + 1; k++) {
3016:             for (PetscInt l = 0; l < 4; l++) {
3017:               vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3018:               vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3019:               vtxCoords[vcount++] = (2 * k - 1) * L;
3020:             }
3021:           }
3022:         }
3023:       }
3024:       // junctions
3025:       for (PetscInt i = 0; i < extent[0]; i++) {
3026:         for (PetscInt j = 0; j < extent[1]; j++) {
3027:           for (PetscInt k = 0; k < extent[2]; k++) {
3028:             const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8;
3029:             PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count");
3030:             for (PetscInt ii = 0; ii < 2; ii++) {
3031:               for (PetscInt jj = 0; jj < 2; jj++) {
3032:                 for (PetscInt kk = 0; kk < 2; kk++) {
3033:                   double Ls           = (1 - sqrt(2) / 4) * L;
3034:                   vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls;
3035:                   vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls;
3036:                   vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls;
3037:                 }
3038:               }
3039:             }
3040:             const PetscInt jfaces[3][2][4] = {
3041:               {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned
3042:               {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned
3043:               {{6, 2, 0, 4}, {7, 3, 1, 5}}  // z-aligned
3044:             };
3045:             const PetscInt pipe_lo[3] = {// vertex numbers of pipes
3046:                                          ((i * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + Npipes[0] + Npipes[1]) * 4};
3047:             const PetscInt pipe_hi[3] = {// vertex numbers of pipes
3048:                                          (((i + 1) * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j + 1) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + 1 + Npipes[0] + Npipes[1]) * 4};
3049:             for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z
3050:               const PetscInt ijk[3] = {i, j, k};
3051:               for (PetscInt l = 0; l < 4; l++) { // rotations
3052:                 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l;
3053:                 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l];
3054:                 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4];
3055:                 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4;
3056:                 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l];
3057:                 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l;
3058:                 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4;
3059:                 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4];
3060:                 if (ijk[dir] == 0) {
3061:                   edges[numEdges][0] = pipe_lo[dir] + l;
3062:                   edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4;
3063:                   edgeSets[numEdges] = dir * 2 + 1;
3064:                   numEdges++;
3065:                 }
3066:                 if (ijk[dir] + 1 == extent[dir]) {
3067:                   edges[numEdges][0] = pipe_hi[dir] + l;
3068:                   edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4;
3069:                   edgeSets[numEdges] = dir * 2 + 2;
3070:                   numEdges++;
3071:                 }
3072:               }
3073:             }
3074:           }
3075:         }
3076:       }
3077:       PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts);
3078:       numFaces   = 24 * Njunctions;
3079:       cells_flat = cells[0][0][0];
3080:     }
3081:     evalFunc   = TPSEvaluate_SchwarzP;
3082:     normalFunc = TPSExtrudeNormalFunc_SchwarzP;
3083:     break;
3084:   case DMPLEX_TPS_GYROID:
3085:     if (rank == 0) {
3086:       // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set
3087:       //
3088:       //     sin(pi*x)*cos(pi*(y+1/2)) + sin(pi*(y+1/2))*cos(pi*(z+1/4)) + sin(pi*(z+1/4))*cos(x)
3089:       //
3090:       // on the cell [0,2]^3.
3091:       //
3092:       // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2].
3093:       // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins
3094:       // like a boomerang:
3095:       //
3096:       //     z = 0          z = 1/4        z = 1/2        z = 3/4     //
3097:       //     -----          -------        -------        -------     //
3098:       //                                                              //
3099:       //     +       +      +       +      +       +      +   \   +   //
3100:       //      \                                   /            \      //
3101:       //       \            `-_   _-'            /              }     //
3102:       //        *-_            `-'            _-'              /      //
3103:       //     +     `-+      +       +      +-'     +      +   /   +   //
3104:       //                                                              //
3105:       //                                                              //
3106:       //     z = 1          z = 5/4        z = 3/2        z = 7/4     //
3107:       //     -----          -------        -------        -------     //
3108:       //                                                              //
3109:       //     +-_     +      +       +      +     _-+      +   /   +   //
3110:       //        `-_            _-_            _-`            /        //
3111:       //           \        _-'   `-_        /              {         //
3112:       //            \                       /                \        //
3113:       //     +       +      +       +      +       +      +   \   +   //
3114:       //
3115:       //
3116:       // This course mesh approximates each of these slices by two line segments,
3117:       // and then connects the segments in consecutive layers with quadrilateral faces.
3118:       // All of the end points of the segments are multiples of 1/4 except for the
3119:       // point * in the picture for z = 0 above and the similar points in other layers.
3120:       // That point is at (gamma, gamma, 0), where gamma is calculated below.
3121:       //
3122:       // The column  [1,2]x[1,2]x[0,2] looks the same as this column;
3123:       // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images.
3124:       //
3125:       // As for how this method turned into the names given to the vertices:
3126:       // that was not systematic, it was just the way it worked out in my handwritten notes.

3128:       PetscInt facesPerBlock = 64;
3129:       PetscInt vertsPerBlock = 56;
3130:       PetscInt extentPlus[3];
3131:       PetscInt numBlocks, numBlocksPlus;
3132:       const PetscInt A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, II = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15, Q = 16, R = 17, S = 18, T = 19, U = 20, V = 21, W = 22, X = 23, Y = 24, Z = 25, Ap = 26, Bp = 27, Cp = 28, Dp = 29, Ep = 30, Fp = 31, Gp = 32, Hp = 33, Ip = 34, Jp = 35, Kp = 36, Lp = 37, Mp = 38, Np = 39, Op = 40, Pp = 41, Qp = 42, Rp = 43, Sp = 44, Tp = 45, Up = 46, Vp = 47, Wp = 48, Xp = 49, Yp = 50, Zp = 51, Aq = 52, Bq = 53, Cq = 54, Dq = 55;
3133:       const PetscInt pattern[64][4] = {
3134:   /* face to vertex within the coarse discretization of a single gyroid block */
3135:   /* layer 0 */
3136:         {A,           C,           K,           G          },
3137:         {C,           B,           II,          K          },
3138:         {D,           A,           H,           L          },
3139:         {B + 56 * 1,  D,           L,           J          },
3140:         {E,           B + 56 * 1,  J,           N          },
3141:         {A + 56 * 2,  E,           N,           H + 56 * 2 },
3142:         {F,           A + 56 * 2,  G + 56 * 2,  M          },
3143:         {B,           F,           M,           II         },
3144:  /* layer 1 */
3145:         {G,           K,           Q,           O          },
3146:         {K,           II,          P,           Q          },
3147:         {L,           H,           O + 56 * 1,  R          },
3148:         {J,           L,           R,           P          },
3149:         {N,           J,           P,           S          },
3150:         {H + 56 * 2,  N,           S,           O + 56 * 3 },
3151:         {M,           G + 56 * 2,  O + 56 * 2,  T          },
3152:         {II,          M,           T,           P          },
3153:  /* layer 2 */
3154:         {O,           Q,           Y,           U          },
3155:         {Q,           P,           W,           Y          },
3156:         {R,           O + 56 * 1,  U + 56 * 1,  Ap         },
3157:         {P,           R,           Ap,          W          },
3158:         {S,           P,           X,           Bp         },
3159:         {O + 56 * 3,  S,           Bp,          V + 56 * 1 },
3160:         {T,           O + 56 * 2,  V,           Z          },
3161:         {P,           T,           Z,           X          },
3162:  /* layer 3 */
3163:         {U,           Y,           Ep,          Dp         },
3164:         {Y,           W,           Cp,          Ep         },
3165:         {Ap,          U + 56 * 1,  Dp + 56 * 1, Gp         },
3166:         {W,           Ap,          Gp,          Cp         },
3167:         {Bp,          X,           Cp + 56 * 2, Fp         },
3168:         {V + 56 * 1,  Bp,          Fp,          Dp + 56 * 1},
3169:         {Z,           V,           Dp,          Hp         },
3170:         {X,           Z,           Hp,          Cp + 56 * 2},
3171:  /* layer 4 */
3172:         {Dp,          Ep,          Mp,          Kp         },
3173:         {Ep,          Cp,          Ip,          Mp         },
3174:         {Gp,          Dp + 56 * 1, Lp,          Np         },
3175:         {Cp,          Gp,          Np,          Jp         },
3176:         {Fp,          Cp + 56 * 2, Jp + 56 * 2, Pp         },
3177:         {Dp + 56 * 1, Fp,          Pp,          Lp         },
3178:         {Hp,          Dp,          Kp,          Op         },
3179:         {Cp + 56 * 2, Hp,          Op,          Ip + 56 * 2},
3180:  /* layer 5 */
3181:         {Kp,          Mp,          Sp,          Rp         },
3182:         {Mp,          Ip,          Qp,          Sp         },
3183:         {Np,          Lp,          Rp,          Tp         },
3184:         {Jp,          Np,          Tp,          Qp + 56 * 1},
3185:         {Pp,          Jp + 56 * 2, Qp + 56 * 3, Up         },
3186:         {Lp,          Pp,          Up,          Rp         },
3187:         {Op,          Kp,          Rp,          Vp         },
3188:         {Ip + 56 * 2, Op,          Vp,          Qp + 56 * 2},
3189:  /* layer 6 */
3190:         {Rp,          Sp,          Aq,          Yp         },
3191:         {Sp,          Qp,          Wp,          Aq         },
3192:         {Tp,          Rp,          Yp,          Cq         },
3193:         {Qp + 56 * 1, Tp,          Cq,          Wp + 56 * 1},
3194:         {Up,          Qp + 56 * 3, Xp + 56 * 1, Dq         },
3195:         {Rp,          Up,          Dq,          Zp         },
3196:         {Vp,          Rp,          Zp,          Bq         },
3197:         {Qp + 56 * 2, Vp,          Bq,          Xp         },
3198:  /* layer 7 (the top is the periodic image of the bottom of layer 0) */
3199:         {Yp,          Aq,          C + 56 * 4,  A + 56 * 4 },
3200:         {Aq,          Wp,          B + 56 * 4,  C + 56 * 4 },
3201:         {Cq,          Yp,          A + 56 * 4,  D + 56 * 4 },
3202:         {Wp + 56 * 1, Cq,          D + 56 * 4,  B + 56 * 5 },
3203:         {Dq,          Xp + 56 * 1, B + 56 * 5,  E + 56 * 4 },
3204:         {Zp,          Dq,          E + 56 * 4,  A + 56 * 6 },
3205:         {Bq,          Zp,          A + 56 * 6,  F + 56 * 4 },
3206:         {Xp,          Bq,          F + 56 * 4,  B + 56 * 4 }
3207:       };
3208:       const PetscReal gamma                = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI;
3209:       const PetscReal patternCoords[56][3] = {
3210:         {1.,        0.,        0.  }, /* A  */
3211:         {0.,        1.,        0.  }, /* B  */
3212:         {gamma,     gamma,     0.  }, /* C  */
3213:         {1 + gamma, 1 - gamma, 0.  }, /* D  */
3214:         {2 - gamma, 2 - gamma, 0.  }, /* E  */
3215:         {1 - gamma, 1 + gamma, 0.  }, /* F  */

3217:         {.5,        0,         .25 }, /* G  */
3218:         {1.5,       0.,        .25 }, /* H  */
3219:         {.5,        1.,        .25 }, /* II */
3220:         {1.5,       1.,        .25 }, /* J  */
3221:         {.25,       .5,        .25 }, /* K  */
3222:         {1.25,      .5,        .25 }, /* L  */
3223:         {.75,       1.5,       .25 }, /* M  */
3224:         {1.75,      1.5,       .25 }, /* N  */

3226:         {0.,        0.,        .5  }, /* O  */
3227:         {1.,        1.,        .5  }, /* P  */
3228:         {gamma,     1 - gamma, .5  }, /* Q  */
3229:         {1 + gamma, gamma,     .5  }, /* R  */
3230:         {2 - gamma, 1 + gamma, .5  }, /* S  */
3231:         {1 - gamma, 2 - gamma, .5  }, /* T  */

3233:         {0.,        .5,        .75 }, /* U  */
3234:         {0.,        1.5,       .75 }, /* V  */
3235:         {1.,        .5,        .75 }, /* W  */
3236:         {1.,        1.5,       .75 }, /* X  */
3237:         {.5,        .75,       .75 }, /* Y  */
3238:         {.5,        1.75,      .75 }, /* Z  */
3239:         {1.5,       .25,       .75 }, /* Ap */
3240:         {1.5,       1.25,      .75 }, /* Bp */

3242:         {1.,        0.,        1.  }, /* Cp */
3243:         {0.,        1.,        1.  }, /* Dp */
3244:         {1 - gamma, 1 - gamma, 1.  }, /* Ep */
3245:         {1 + gamma, 1 + gamma, 1.  }, /* Fp */
3246:         {2 - gamma, gamma,     1.  }, /* Gp */
3247:         {gamma,     2 - gamma, 1.  }, /* Hp */

3249:         {.5,        0.,        1.25}, /* Ip */
3250:         {1.5,       0.,        1.25}, /* Jp */
3251:         {.5,        1.,        1.25}, /* Kp */
3252:         {1.5,       1.,        1.25}, /* Lp */
3253:         {.75,       .5,        1.25}, /* Mp */
3254:         {1.75,      .5,        1.25}, /* Np */
3255:         {.25,       1.5,       1.25}, /* Op */
3256:         {1.25,      1.5,       1.25}, /* Pp */

3258:         {0.,        0.,        1.5 }, /* Qp */
3259:         {1.,        1.,        1.5 }, /* Rp */
3260:         {1 - gamma, gamma,     1.5 }, /* Sp */
3261:         {2 - gamma, 1 - gamma, 1.5 }, /* Tp */
3262:         {1 + gamma, 2 - gamma, 1.5 }, /* Up */
3263:         {gamma,     1 + gamma, 1.5 }, /* Vp */

3265:         {0.,        .5,        1.75}, /* Wp */
3266:         {0.,        1.5,       1.75}, /* Xp */
3267:         {1.,        .5,        1.75}, /* Yp */
3268:         {1.,        1.5,       1.75}, /* Zp */
3269:         {.5,        .25,       1.75}, /* Aq */
3270:         {.5,        1.25,      1.75}, /* Bq */
3271:         {1.5,       .75,       1.75}, /* Cq */
3272:         {1.5,       1.75,      1.75}, /* Dq */
3273:       };
3274:       PetscInt(*cells)[64][4] = NULL;
3275:       PetscBool *seen;
3276:       PetscInt  *vertToTrueVert;
3277:       PetscInt   count;

3279:       for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1;
3280:       numBlocks = 1;
3281:       for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i];
3282:       numBlocksPlus = 1;
3283:       for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i];
3284:       numFaces = numBlocks * facesPerBlock;
3285:       PetscCall(PetscMalloc1(numBlocks, &cells));
3286:       PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen));
3287:       for (PetscInt k = 0; k < extent[2]; k++) {
3288:         for (PetscInt j = 0; j < extent[1]; j++) {
3289:           for (PetscInt i = 0; i < extent[0]; i++) {
3290:             for (PetscInt f = 0; f < facesPerBlock; f++) {
3291:               for (PetscInt v = 0; v < 4; v++) {
3292:                 PetscInt vertRaw     = pattern[f][v];
3293:                 PetscInt blockidx    = vertRaw / 56;
3294:                 PetscInt patternvert = vertRaw % 56;
3295:                 PetscInt xplus       = (blockidx & 1);
3296:                 PetscInt yplus       = (blockidx & 2) >> 1;
3297:                 PetscInt zplus       = (blockidx & 4) >> 2;
3298:                 PetscInt zcoord      = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus);
3299:                 PetscInt ycoord      = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus);
3300:                 PetscInt xcoord      = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus);
3301:                 PetscInt vert        = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert;

3303:                 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert;
3304:                 seen[vert]                                       = PETSC_TRUE;
3305:               }
3306:             }
3307:           }
3308:         }
3309:       }
3310:       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++)
3311:         if (seen[i]) numVertices++;
3312:       count = 0;
3313:       PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert));
3314:       PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords));
3315:       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1;
3316:       for (PetscInt k = 0; k < extentPlus[2]; k++) {
3317:         for (PetscInt j = 0; j < extentPlus[1]; j++) {
3318:           for (PetscInt i = 0; i < extentPlus[0]; i++) {
3319:             for (PetscInt v = 0; v < vertsPerBlock; v++) {
3320:               PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v;

3322:               if (seen[vIdx]) {
3323:                 PetscInt thisVert;

3325:                 vertToTrueVert[vIdx] = thisVert = count++;

3327:                 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d];
3328:                 vtxCoords[3 * thisVert + 0] += i * 2;
3329:                 vtxCoords[3 * thisVert + 1] += j * 2;
3330:                 vtxCoords[3 * thisVert + 2] += k * 2;
3331:               }
3332:             }
3333:           }
3334:         }
3335:       }
3336:       for (PetscInt i = 0; i < numBlocks; i++) {
3337:         for (PetscInt f = 0; f < facesPerBlock; f++) {
3338:           for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]];
3339:         }
3340:       }
3341:       PetscCall(PetscFree(vertToTrueVert));
3342:       PetscCall(PetscFree(seen));
3343:       cells_flat = cells[0][0];
3344:       numEdges   = 0;
3345:       for (PetscInt i = 0; i < numFaces; i++) {
3346:         for (PetscInt e = 0; e < 4; e++) {
3347:           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3348:           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};

3350:           for (PetscInt d = 0; d < 3; d++) {
3351:             if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) {
3352:               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++;
3353:               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++;
3354:             }
3355:           }
3356:         }
3357:       }
3358:       PetscCall(PetscMalloc1(numEdges, &edges));
3359:       PetscCall(PetscMalloc1(numEdges, &edgeSets));
3360:       for (PetscInt edge = 0, i = 0; i < numFaces; i++) {
3361:         for (PetscInt e = 0; e < 4; e++) {
3362:           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3363:           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};

3365:           for (PetscInt d = 0; d < 3; d++) {
3366:             if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) {
3367:               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) {
3368:                 edges[edge][0]   = ev[0];
3369:                 edges[edge][1]   = ev[1];
3370:                 edgeSets[edge++] = 2 * d;
3371:               }
3372:               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) {
3373:                 edges[edge][0]   = ev[0];
3374:                 edges[edge][1]   = ev[1];
3375:                 edgeSets[edge++] = 2 * d + 1;
3376:               }
3377:             }
3378:           }
3379:         }
3380:       }
3381:     }
3382:     evalFunc   = TPSEvaluate_Gyroid;
3383:     normalFunc = TPSExtrudeNormalFunc_Gyroid;
3384:     break;
3385:   }

3387:   PetscCall(DMSetDimension(dm, topoDim));
3388:   if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat));
3389:   else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL));
3390:   PetscCall(PetscFree(cells_flat));
3391:   {
3392:     DM idm;
3393:     PetscCall(DMPlexInterpolate(dm, &idm));
3394:     PetscCall(DMPlexReplace_Internal(dm, &idm));
3395:   }
3396:   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords));
3397:   else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL));
3398:   PetscCall(PetscFree(vtxCoords));

3400:   PetscCall(DMCreateLabel(dm, "Face Sets"));
3401:   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3402:   for (PetscInt e = 0; e < numEdges; e++) {
3403:     PetscInt        njoin;
3404:     const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]};
3405:     PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join));
3406:     PetscCheck(njoin == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected unique join of vertices %" PetscInt_FMT " and %" PetscInt_FMT, edges[e][0], edges[e][1]);
3407:     PetscCall(DMLabelSetValue(label, join[0], edgeSets[e]));
3408:     PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join));
3409:   }
3410:   PetscCall(PetscFree(edges));
3411:   PetscCall(PetscFree(edgeSets));
3412:   if (tps_distribute) {
3413:     DM               pdm = NULL;
3414:     PetscPartitioner part;

3416:     PetscCall(DMPlexGetPartitioner(dm, &part));
3417:     PetscCall(PetscPartitionerSetFromOptions(part));
3418:     PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm));
3419:     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
3420:     // Do not auto-distribute again
3421:     PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
3422:   }

3424:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
3425:   for (PetscInt refine = 0; refine < refinements; refine++) {
3426:     PetscInt     m;
3427:     DM           dmf;
3428:     Vec          X;
3429:     PetscScalar *x;
3430:     PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf));
3431:     PetscCall(DMPlexReplace_Internal(dm, &dmf));

3433:     PetscCall(DMGetCoordinatesLocal(dm, &X));
3434:     PetscCall(VecGetLocalSize(X, &m));
3435:     PetscCall(VecGetArray(X, &x));
3436:     for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i]));
3437:     PetscCall(VecRestoreArray(X, &x));
3438:   }

3440:   // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices.
3441:   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3442:   PetscCall(DMPlexLabelComplete(dm, label));

3444:   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));

3446:   if (thickness > 0) {
3447:     DM              edm, cdm, ecdm;
3448:     DMPlexTransform tr;
3449:     const char     *prefix;
3450:     PetscOptions    options;
3451:     // Code from DMPlexExtrude
3452:     PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
3453:     PetscCall(DMPlexTransformSetDM(tr, dm));
3454:     PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE));
3455:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
3456:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
3457:     PetscCall(PetscObjectGetOptions((PetscObject)dm, &options));
3458:     PetscCall(PetscObjectSetOptions((PetscObject)tr, options));
3459:     PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers));
3460:     PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness));
3461:     PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE));
3462:     PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE));
3463:     PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc));
3464:     PetscCall(DMPlexTransformSetFromOptions(tr));
3465:     PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
3466:     PetscCall(DMPlexTransformSetUp(tr));
3467:     PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view"));
3468:     PetscCall(DMPlexTransformApply(tr, dm, &edm));
3469:     PetscCall(DMCopyDisc(dm, edm));
3470:     PetscCall(DMGetCoordinateDM(dm, &cdm));
3471:     PetscCall(DMGetCoordinateDM(edm, &ecdm));
3472:     PetscCall(DMCopyDisc(cdm, ecdm));
3473:     PetscCall(DMPlexTransformCreateDiscLabels(tr, edm));
3474:     PetscCall(DMPlexTransformDestroy(&tr));
3475:     if (edm) {
3476:       ((DM_Plex *)edm->data)->printFEM    = ((DM_Plex *)dm->data)->printFEM;
3477:       ((DM_Plex *)edm->data)->printL2     = ((DM_Plex *)dm->data)->printL2;
3478:       ((DM_Plex *)edm->data)->printLocate = ((DM_Plex *)dm->data)->printLocate;
3479:     }
3480:     PetscCall(DMPlexReplace_Internal(dm, &edm));
3481:   }
3482:   PetscFunctionReturn(PETSC_SUCCESS);
3483: }

3485: /*@
3486:   DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface

3488:   Collective

3490:   Input Parameters:
3491: + comm   - The communicator for the `DM` object
3492: . tpstype - Type of triply-periodic surface
3493: . extent - Array of length 3 containing number of periods in each direction
3494: . periodic - array of length 3 with periodicity, or NULL for non-periodic
3495: . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable)
3496: . refinements - Number of factor-of-2 refinements of 2D manifold mesh
3497: . layers - Number of cell layers extruded in normal direction
3498: - thickness - Thickness in normal direction

3500:   Output Parameter:
3501: . dm  - The `DM` object

3503:   Level: beginner

3505:   Notes:
3506:   This meshes the surface of the Schwarz P or Gyroid surfaces.  Schwarz P is is the simplest member of the triply-periodic minimal surfaces.
3507:   https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22) and can be cut with "clean" boundaries.
3508:   The Gyroid (https://en.wikipedia.org/wiki/Gyroid) is another triply-periodic minimal surface with applications in additive manufacturing; it is much more difficult to "cut" since there are no planes of symmetry.
3509:   Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested.
3510:   On each refinement, all vertices are projected to their nearest point on the surface.
3511:   This projection could readily be extended to related surfaces.

3513:   The face (edge) sets for the Schwarz P surface are numbered 1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z).
3514:   When the mesh is refined, "Face Sets" contain the new vertices (created during refinement).  Use DMPlexLabelComplete() to propagate to coarse-level vertices.

3516:   Developer Note:
3517:   The Gyroid mesh does not currently mark boundary sets.

3519:   References:
3520: . * - Maskery et al, Insights into the mechanical properties of several triply periodic minimal surface lattice structures made by polymer additive manufacturing, 2017.
3521:     https://doi.org/10.1016/j.polymer.2017.11.049

3523: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()`
3524: @*/
3525: PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm)
3526: {
3527:   PetscFunctionBegin;
3528:   PetscCall(DMCreate(comm, dm));
3529:   PetscCall(DMSetType(*dm, DMPLEX));
3530:   PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness));
3531:   PetscFunctionReturn(PETSC_SUCCESS);
3532: }

3534: /*@
3535:   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.

3537:   Collective

3539:   Input Parameters:
3540: + comm    - The communicator for the `DM` object
3541: . dim     - The dimension
3542: . simplex - Use simplices, or tensor product cells
3543: - R       - The radius

3545:   Output Parameter:
3546: . dm  - The `DM` object

3548:   Level: beginner

3550: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3551: @*/
3552: PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
3553: {
3554:   PetscFunctionBegin;
3556:   PetscCall(DMCreate(comm, dm));
3557:   PetscCall(DMSetType(*dm, DMPLEX));
3558:   PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R));
3559:   PetscFunctionReturn(PETSC_SUCCESS);
3560: }

3562: static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R)
3563: {
3564:   DM      sdm, vol;
3565:   DMLabel bdlabel;

3567:   PetscFunctionBegin;
3568:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
3569:   PetscCall(DMSetType(sdm, DMPLEX));
3570:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sdm, "bd_"));
3571:   PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R));
3572:   PetscCall(DMSetFromOptions(sdm));
3573:   PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view"));
3574:   PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol));
3575:   PetscCall(DMDestroy(&sdm));
3576:   PetscCall(DMPlexReplace_Internal(dm, &vol));
3577:   PetscCall(DMCreateLabel(dm, "marker"));
3578:   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
3579:   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
3580:   PetscCall(DMPlexLabelComplete(dm, bdlabel));
3581:   PetscFunctionReturn(PETSC_SUCCESS);
3582: }

3584: /*@
3585:   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.

3587:   Collective

3589:   Input Parameters:
3590: + comm  - The communicator for the `DM` object
3591: . dim   - The dimension
3592: - R     - The radius

3594:   Output Parameter:
3595: . dm  - The `DM` object

3597:   Options Database Key:
3598: - bd_dm_refine - This will refine the surface mesh preserving the sphere geometry

3600:   Level: beginner

3602: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3603: @*/
3604: PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
3605: {
3606:   PetscFunctionBegin;
3607:   PetscCall(DMCreate(comm, dm));
3608:   PetscCall(DMSetType(*dm, DMPLEX));
3609:   PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R));
3610:   PetscFunctionReturn(PETSC_SUCCESS);
3611: }

3613: static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct)
3614: {
3615:   PetscFunctionBegin;
3616:   switch (ct) {
3617:   case DM_POLYTOPE_POINT: {
3618:     PetscInt    numPoints[1]        = {1};
3619:     PetscInt    coneSize[1]         = {0};
3620:     PetscInt    cones[1]            = {0};
3621:     PetscInt    coneOrientations[1] = {0};
3622:     PetscScalar vertexCoords[1]     = {0.0};

3624:     PetscCall(DMSetDimension(rdm, 0));
3625:     PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3626:   } break;
3627:   case DM_POLYTOPE_SEGMENT: {
3628:     PetscInt    numPoints[2]        = {2, 1};
3629:     PetscInt    coneSize[3]         = {2, 0, 0};
3630:     PetscInt    cones[2]            = {1, 2};
3631:     PetscInt    coneOrientations[2] = {0, 0};
3632:     PetscScalar vertexCoords[2]     = {-1.0, 1.0};

3634:     PetscCall(DMSetDimension(rdm, 1));
3635:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3636:   } break;
3637:   case DM_POLYTOPE_POINT_PRISM_TENSOR: {
3638:     PetscInt    numPoints[2]        = {2, 1};
3639:     PetscInt    coneSize[3]         = {2, 0, 0};
3640:     PetscInt    cones[2]            = {1, 2};
3641:     PetscInt    coneOrientations[2] = {0, 0};
3642:     PetscScalar vertexCoords[2]     = {-1.0, 1.0};

3644:     PetscCall(DMSetDimension(rdm, 1));
3645:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3646:   } break;
3647:   case DM_POLYTOPE_TRIANGLE: {
3648:     PetscInt    numPoints[2]        = {3, 1};
3649:     PetscInt    coneSize[4]         = {3, 0, 0, 0};
3650:     PetscInt    cones[3]            = {1, 2, 3};
3651:     PetscInt    coneOrientations[3] = {0, 0, 0};
3652:     PetscScalar vertexCoords[6]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0};

3654:     PetscCall(DMSetDimension(rdm, 2));
3655:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3656:   } break;
3657:   case DM_POLYTOPE_QUADRILATERAL: {
3658:     PetscInt    numPoints[2]        = {4, 1};
3659:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3660:     PetscInt    cones[4]            = {1, 2, 3, 4};
3661:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3662:     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0};

3664:     PetscCall(DMSetDimension(rdm, 2));
3665:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3666:   } break;
3667:   case DM_POLYTOPE_SEG_PRISM_TENSOR: {
3668:     PetscInt    numPoints[2]        = {4, 1};
3669:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3670:     PetscInt    cones[4]            = {1, 2, 3, 4};
3671:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3672:     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};

3674:     PetscCall(DMSetDimension(rdm, 2));
3675:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3676:   } break;
3677:   case DM_POLYTOPE_TETRAHEDRON: {
3678:     PetscInt    numPoints[2]        = {4, 1};
3679:     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3680:     PetscInt    cones[4]            = {1, 2, 3, 4};
3681:     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3682:     PetscScalar vertexCoords[12]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0};

3684:     PetscCall(DMSetDimension(rdm, 3));
3685:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3686:   } break;
3687:   case DM_POLYTOPE_HEXAHEDRON: {
3688:     PetscInt    numPoints[2]        = {8, 1};
3689:     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3690:     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3691:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3692:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};

3694:     PetscCall(DMSetDimension(rdm, 3));
3695:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3696:   } break;
3697:   case DM_POLYTOPE_TRI_PRISM: {
3698:     PetscInt    numPoints[2]        = {6, 1};
3699:     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3700:     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3701:     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3702:     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};

3704:     PetscCall(DMSetDimension(rdm, 3));
3705:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3706:   } break;
3707:   case DM_POLYTOPE_TRI_PRISM_TENSOR: {
3708:     PetscInt    numPoints[2]        = {6, 1};
3709:     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3710:     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3711:     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3712:     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};

3714:     PetscCall(DMSetDimension(rdm, 3));
3715:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3716:   } break;
3717:   case DM_POLYTOPE_QUAD_PRISM_TENSOR: {
3718:     PetscInt    numPoints[2]        = {8, 1};
3719:     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3720:     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3721:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3722:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};

3724:     PetscCall(DMSetDimension(rdm, 3));
3725:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3726:   } break;
3727:   case DM_POLYTOPE_PYRAMID: {
3728:     PetscInt    numPoints[2]        = {5, 1};
3729:     PetscInt    coneSize[6]         = {5, 0, 0, 0, 0, 0};
3730:     PetscInt    cones[5]            = {1, 2, 3, 4, 5};
3731:     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3732:     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0};

3734:     PetscCall(DMSetDimension(rdm, 3));
3735:     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3736:   } break;
3737:   default:
3738:     SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
3739:   }
3740:   {
3741:     PetscInt Nv, v;

3743:     /* Must create the celltype label here so that we do not automatically try to compute the types */
3744:     PetscCall(DMCreateLabel(rdm, "celltype"));
3745:     PetscCall(DMPlexSetCellType(rdm, 0, ct));
3746:     PetscCall(DMPlexGetChart(rdm, NULL, &Nv));
3747:     for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT));
3748:   }
3749:   PetscCall(DMPlexInterpolateInPlace_Internal(rdm));
3750:   PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct]));
3751:   PetscFunctionReturn(PETSC_SUCCESS);
3752: }

3754: /*@
3755:   DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell

3757:   Collective

3759:   Input Parameters:
3760: + comm - The communicator
3761: - ct   - The cell type of the reference cell

3763:   Output Parameter:
3764: . refdm - The reference cell

3766:   Level: intermediate

3768: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateReferenceCell()`, `DMPlexCreateBoxMesh()`
3769: @*/
3770: PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
3771: {
3772:   PetscFunctionBegin;
3773:   PetscCall(DMCreate(comm, refdm));
3774:   PetscCall(DMSetType(*refdm, DMPLEX));
3775:   PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct));
3776:   PetscFunctionReturn(PETSC_SUCCESS);
3777: }

3779: static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[])
3780: {
3781:   DM        plex;
3782:   DMLabel   label;
3783:   PetscBool hasLabel;

3785:   PetscFunctionBegin;
3786:   PetscCall(DMHasLabel(dm, name, &hasLabel));
3787:   if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS);
3788:   PetscCall(DMCreateLabel(dm, name));
3789:   PetscCall(DMGetLabel(dm, name, &label));
3790:   PetscCall(DMConvert(dm, DMPLEX, &plex));
3791:   PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label));
3792:   PetscCall(DMPlexLabelComplete(plex, label));
3793:   PetscCall(DMDestroy(&plex));
3794:   PetscFunctionReturn(PETSC_SUCCESS);
3795: }

3797: /*
3798:   We use the last coordinate as the radius, the inner radius is lower[dim-1] and the outer radius is upper[dim-1]. Then we map the first coordinate around the circle.

3800:     (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0]))
3801: */
3802: static void boxToAnnulus(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
3803: {
3804:   const PetscReal low = PetscRealPart(constants[0]);
3805:   const PetscReal upp = PetscRealPart(constants[1]);
3806:   const PetscReal r   = PetscRealPart(u[1]);
3807:   const PetscReal th  = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low);

3809:   f0[0] = r * PetscCosReal(th);
3810:   f0[1] = r * PetscSinReal(th);
3811: }

3813: const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL};

3815: static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems *PetscOptionsObject, PetscBool *useCoordSpace, DM dm)
3816: {
3817:   DMPlexShape    shape   = DM_SHAPE_BOX;
3818:   DMPolytopeType cell    = DM_POLYTOPE_TRIANGLE;
3819:   PetscInt       dim     = 2;
3820:   PetscBool      simplex = PETSC_TRUE, interpolate = PETSC_TRUE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE;
3821:   PetscBool      flg, flg2, fflg, bdfflg, nameflg;
3822:   MPI_Comm       comm;
3823:   char           filename[PETSC_MAX_PATH_LEN]   = "<unspecified>";
3824:   char           bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>";
3825:   char           plexname[PETSC_MAX_PATH_LEN]   = "";

3827:   PetscFunctionBegin;
3828:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3829:   /* TODO Turn this into a registration interface */
3830:   PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg));
3831:   PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg));
3832:   PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg));
3833:   PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL));
3834:   PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL));
3835:   PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg));
3836:   PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0));
3837:   PetscCheck(dim >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " should be in [0, infinity)", dim);
3838:   PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg));
3839:   PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg));
3840:   PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg));
3841:   PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2));
3842:   if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure));

3844:   switch (cell) {
3845:   case DM_POLYTOPE_POINT:
3846:   case DM_POLYTOPE_SEGMENT:
3847:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
3848:   case DM_POLYTOPE_TRIANGLE:
3849:   case DM_POLYTOPE_QUADRILATERAL:
3850:   case DM_POLYTOPE_TETRAHEDRON:
3851:   case DM_POLYTOPE_HEXAHEDRON:
3852:     *useCoordSpace = PETSC_TRUE;
3853:     break;
3854:   default:
3855:     *useCoordSpace = PETSC_FALSE;
3856:     break;
3857:   }

3859:   if (fflg) {
3860:     DM dmnew;

3862:     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, plexname, interpolate, &dmnew));
3863:     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3864:     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3865:   } else if (refDomain) {
3866:     PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell));
3867:   } else if (bdfflg) {
3868:     DM bdm, dmnew;

3870:     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, plexname, interpolate, &bdm));
3871:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_"));
3872:     PetscCall(DMSetFromOptions(bdm));
3873:     PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew));
3874:     PetscCall(DMDestroy(&bdm));
3875:     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3876:     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3877:   } else {
3878:     PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape]));
3879:     switch (shape) {
3880:     case DM_SHAPE_BOX:
3881:     case DM_SHAPE_ZBOX:
3882:     case DM_SHAPE_ANNULUS: {
3883:       PetscInt       faces[3]  = {0, 0, 0};
3884:       PetscReal      lower[3]  = {0, 0, 0};
3885:       PetscReal      upper[3]  = {1, 1, 1};
3886:       DMBoundaryType bdt[3]    = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
3887:       PetscBool      isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE;
3888:       PetscInt       i, n;

3890:       n = dim;
3891:       for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim);
3892:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
3893:       n = 3;
3894:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
3895:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3896:       n = 3;
3897:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
3898:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3899:       n = 3;
3900:       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
3901:       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);

3903:       PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented");
3904:       if (isAnnular)
3905:         for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC;

3907:       switch (cell) {
3908:       case DM_POLYTOPE_TRI_PRISM_TENSOR:
3909:         PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt));
3910:         if (!interpolate) {
3911:           DM udm;

3913:           PetscCall(DMPlexUninterpolate(dm, &udm));
3914:           PetscCall(DMPlexReplace_Internal(dm, &udm));
3915:         }
3916:         break;
3917:       default:
3918:         PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate));
3919:         break;
3920:       }
3921:       if (isAnnular) {
3922:         DM          cdm;
3923:         PetscDS     cds;
3924:         PetscScalar bounds[2] = {lower[0], upper[0]};

3926:         // Fix coordinates for annular region
3927:         PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
3928:         PetscCall(DMSetCellCoordinatesLocal(dm, NULL));
3929:         PetscCall(DMSetCellCoordinates(dm, NULL));
3930:         PetscCall(DMPlexCreateCoordinateSpace(dm, 1, NULL));
3931:         PetscCall(DMGetCoordinateDM(dm, &cdm));
3932:         PetscCall(DMGetDS(cdm, &cds));
3933:         PetscCall(PetscDSSetConstants(cds, 2, bounds));
3934:         PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus));
3935:       }
3936:     } break;
3937:     case DM_SHAPE_BOX_SURFACE: {
3938:       PetscInt  faces[3] = {0, 0, 0};
3939:       PetscReal lower[3] = {0, 0, 0};
3940:       PetscReal upper[3] = {1, 1, 1};
3941:       PetscInt  i, n;

3943:       n = dim + 1;
3944:       for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1));
3945:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
3946:       n = 3;
3947:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
3948:       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
3949:       n = 3;
3950:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
3951:       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
3952:       PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate));
3953:     } break;
3954:     case DM_SHAPE_SPHERE: {
3955:       PetscReal R = 1.0;

3957:       PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg));
3958:       PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R));
3959:     } break;
3960:     case DM_SHAPE_BALL: {
3961:       PetscReal R = 1.0;

3963:       PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg));
3964:       PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R));
3965:     } break;
3966:     case DM_SHAPE_CYLINDER: {
3967:       DMBoundaryType bdt = DM_BOUNDARY_NONE;
3968:       PetscInt       Nw  = 6;

3970:       PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL));
3971:       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL));
3972:       switch (cell) {
3973:       case DM_POLYTOPE_TRI_PRISM_TENSOR:
3974:         PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate));
3975:         break;
3976:       default:
3977:         PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt));
3978:         break;
3979:       }
3980:     } break;
3981:     case DM_SHAPE_SCHWARZ_P: // fallthrough
3982:     case DM_SHAPE_GYROID: {
3983:       PetscInt       extent[3] = {1, 1, 1}, refine = 0, layers = 0, three;
3984:       PetscReal      thickness   = 0.;
3985:       DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
3986:       DMPlexTPSType  tps_type    = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID;
3987:       PetscBool      tps_distribute;
3988:       PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL));
3989:       PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL));
3990:       PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL));
3991:       PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL));
3992:       PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL));
3993:       PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute));
3994:       PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL));
3995:       PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness));
3996:     } break;
3997:     case DM_SHAPE_DOUBLET: {
3998:       DM        dmnew;
3999:       PetscReal rl = 0.0;

4001:       PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL));
4002:       PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew));
4003:       PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4004:       PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4005:     } break;
4006:     case DM_SHAPE_HYPERCUBIC: {
4007:       PetscInt       *edges;
4008:       PetscReal      *lower, *upper;
4009:       DMBoundaryType *bdt;
4010:       PetscInt        n, d;

4012:       *useCoordSpace = PETSC_FALSE;
4013:       PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt));
4014:       for (d = 0; d < dim; ++d) {
4015:         edges[d] = 1;
4016:         lower[d] = 0.;
4017:         upper[d] = 1.;
4018:         bdt[d]   = DM_BOUNDARY_PERIODIC;
4019:       }
4020:       n = dim;
4021:       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg));
4022:       n = dim;
4023:       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4024:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4025:       n = dim;
4026:       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4027:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4028:       n = dim;
4029:       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4030:       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4031:       PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt));
4032:       PetscCall(PetscFree4(edges, lower, upper, bdt));
4033:     } break;
4034:     default:
4035:       SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]);
4036:     }
4037:   }
4038:   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4039:   if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname));
4040:   PetscFunctionReturn(PETSC_SUCCESS);
4041: }

4043: PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4044: {
4045:   DM_Plex  *mesh = (DM_Plex *)dm->data;
4046:   PetscBool flg, flg2;
4047:   char      bdLabel[PETSC_MAX_PATH_LEN];

4049:   PetscFunctionBegin;
4050:   /* Handle viewing */
4051:   PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL));
4052:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0));
4053:   PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL));
4054:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0));
4055:   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0));
4056:   PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg));
4057:   if (flg) PetscCall(PetscLogDefaultBegin());
4058:   /* Labeling */
4059:   PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg));
4060:   if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel));
4061:   /* Point Location */
4062:   PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL));
4063:   /* Partitioning and distribution */
4064:   PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL));
4065:   /* Generation and remeshing */
4066:   PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL));
4067:   /* Projection behavior */
4068:   PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0));
4069:   PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL));
4070:   /* Checking structure */
4071:   {
4072:     PetscBool all = PETSC_FALSE;

4074:     PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL));
4075:     if (all) {
4076:       PetscCall(DMPlexCheck(dm));
4077:     } else {
4078:       PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2));
4079:       if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm));
4080:       PetscCall(PetscOptionsBool("-dm_plex_check_skeleton", "Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes)", "DMPlexCheckSkeleton", PETSC_FALSE, &flg, &flg2));
4081:       if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0));
4082:       PetscCall(PetscOptionsBool("-dm_plex_check_faces", "Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type", "DMPlexCheckFaces", PETSC_FALSE, &flg, &flg2));
4083:       if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0));
4084:       PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2));
4085:       if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm));
4086:       PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2));
4087:       if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
4088:       PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2));
4089:       if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm));
4090:     }
4091:     PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2));
4092:     if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE));
4093:   }
4094:   {
4095:     PetscReal scale = 1.0;

4097:     PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg));
4098:     if (flg) {
4099:       Vec coordinates, coordinatesLocal;

4101:       PetscCall(DMGetCoordinates(dm, &coordinates));
4102:       PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
4103:       PetscCall(VecScale(coordinates, scale));
4104:       PetscCall(VecScale(coordinatesLocal, scale));
4105:     }
4106:   }
4107:   PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner));
4108:   PetscFunctionReturn(PETSC_SUCCESS);
4109: }

4111: PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap)
4112: {
4113:   PetscInt  numOvLabels = 16, numOvExLabels = 16;
4114:   char     *ovLabelNames[16], *ovExLabelNames[16];
4115:   PetscInt  numOvValues = 16, numOvExValues = 16, l;
4116:   PetscBool flg;

4118:   PetscFunctionBegin;
4119:   PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0));
4120:   PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg));
4121:   if (!flg) numOvLabels = 0;
4122:   if (numOvLabels) {
4123:     ((DM_Plex *)dm->data)->numOvLabels = numOvLabels;
4124:     for (l = 0; l < numOvLabels; ++l) {
4125:       PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l]));
4126:       PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]);
4127:       PetscCall(PetscFree(ovLabelNames[l]));
4128:     }
4129:     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg));
4130:     if (!flg) numOvValues = 0;
4131:     PetscCheck(numOvLabels == numOvValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvLabels, numOvValues);

4133:     PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg));
4134:     if (!flg) numOvExLabels = 0;
4135:     ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels;
4136:     for (l = 0; l < numOvExLabels; ++l) {
4137:       PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l]));
4138:       PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]);
4139:       PetscCall(PetscFree(ovExLabelNames[l]));
4140:     }
4141:     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg));
4142:     if (!flg) numOvExValues = 0;
4143:     PetscCheck(numOvExLabels == numOvExValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of exclude labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvExLabels, numOvExValues);
4144:   }
4145:   PetscFunctionReturn(PETSC_SUCCESS);
4146: }

4148: static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4149: {
4150:   PetscFunctionList        ordlist;
4151:   char                     oname[256];
4152:   PetscReal                volume    = -1.0;
4153:   PetscInt                 prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim;
4154:   PetscBool                uniformOrig, created = PETSC_FALSE, uniform = PETSC_TRUE, distribute, interpolate = PETSC_TRUE, coordSpace = PETSC_TRUE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, ignoreModel = PETSC_FALSE, flg;
4155:   DMPlexReorderDefaultFlag reorder;

4157:   PetscFunctionBegin;
4158:   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options");
4159:   if (dm->cloneOpts) goto non_refine;
4160:   /* Handle automatic creation */
4161:   PetscCall(DMGetDimension(dm, &dim));
4162:   if (dim < 0) {
4163:     PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm));
4164:     created = PETSC_TRUE;
4165:   }
4166:   PetscCall(DMGetDimension(dm, &dim));
4167:   /* Handle interpolation before distribution */
4168:   PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg));
4169:   if (flg) {
4170:     DMPlexInterpolatedFlag interpolated;

4172:     PetscCall(DMPlexIsInterpolated(dm, &interpolated));
4173:     if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) {
4174:       DM udm;

4176:       PetscCall(DMPlexUninterpolate(dm, &udm));
4177:       PetscCall(DMPlexReplace_Internal(dm, &udm));
4178:     } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) {
4179:       DM idm;

4181:       PetscCall(DMPlexInterpolate(dm, &idm));
4182:       PetscCall(DMPlexReplace_Internal(dm, &idm));
4183:     }
4184:   }
4185:   /* Handle DMPlex refinement before distribution */
4186:   PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg));
4187:   if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel;
4188:   PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig));
4189:   PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0));
4190:   PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4191:   PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg));
4192:   if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform));
4193:   PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg));
4194:   if (flg) {
4195:     PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE));
4196:     PetscCall(DMPlexSetRefinementLimit(dm, volume));
4197:     prerefine = PetscMax(prerefine, 1);
4198:   }
4199:   for (r = 0; r < prerefine; ++r) {
4200:     DM             rdm;
4201:     PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4203:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4204:     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4205:     PetscCall(DMPlexReplace_Internal(dm, &rdm));
4206:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4207:     if (coordFunc && remap) {
4208:       PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4209:       ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4210:     }
4211:   }
4212:   PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig));
4213:   /* Handle DMPlex extrusion before distribution */
4214:   PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0));
4215:   if (extLayers) {
4216:     DM edm;

4218:     PetscCall(DMExtrude(dm, extLayers, &edm));
4219:     PetscCall(DMPlexReplace_Internal(dm, &edm));
4220:     ((DM_Plex *)dm->data)->coordFunc = NULL;
4221:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4222:     extLayers = 0;
4223:     PetscCall(DMGetDimension(dm, &dim));
4224:   }
4225:   /* Handle DMPlex reordering before distribution */
4226:   PetscCall(DMPlexReorderGetDefault(dm, &reorder));
4227:   PetscCall(MatGetOrderingList(&ordlist));
4228:   PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname)));
4229:   PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg));
4230:   if (reorder == DMPLEX_REORDER_DEFAULT_TRUE || flg) {
4231:     DM pdm;
4232:     IS perm;

4234:     PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm));
4235:     PetscCall(DMPlexPermute(dm, perm, &pdm));
4236:     PetscCall(ISDestroy(&perm));
4237:     PetscCall(DMPlexReplace_Internal(dm, &pdm));
4238:     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4239:   }
4240:   /* Handle DMPlex distribution */
4241:   PetscCall(DMPlexDistributeGetDefault(dm, &distribute));
4242:   PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL));
4243:   PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
4244:   if (distribute) {
4245:     DM               pdm = NULL;
4246:     PetscPartitioner part;

4248:     PetscCall(DMPlexGetPartitioner(dm, &part));
4249:     PetscCall(PetscPartitionerSetFromOptions(part));
4250:     PetscCall(DMPlexDistribute(dm, overlap, NULL, &pdm));
4251:     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
4252:   }
4253:   /* Create coordinate space */
4254:   if (created) {
4255:     DM_Plex  *mesh   = (DM_Plex *)dm->data;
4256:     PetscInt  degree = 1;
4257:     PetscInt  height = 0;
4258:     DM        cdm;
4259:     PetscBool flg;

4261:     PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg));
4262:     PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, &degree, NULL));
4263:     if (coordSpace) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, mesh->coordFunc));
4264:     PetscCall(DMGetCoordinateDM(dm, &cdm));
4265:     if (flg && !coordSpace) {
4266:       PetscDS      cds;
4267:       PetscObject  obj;
4268:       PetscClassId id;

4270:       PetscCall(DMGetDS(cdm, &cds));
4271:       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4272:       PetscCall(PetscObjectGetClassId(obj, &id));
4273:       if (id == PETSCFE_CLASSID) {
4274:         PetscContainer dummy;

4276:         PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy));
4277:         PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates"));
4278:         PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy));
4279:         PetscCall(PetscContainerDestroy(&dummy));
4280:         PetscCall(DMClearDS(cdm));
4281:       }
4282:       mesh->coordFunc = NULL;
4283:     }
4284:     PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "", dm->sparseLocalize, &dm->sparseLocalize, &flg));
4285:     PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg));
4286:     if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height));
4287:     PetscCall(DMLocalizeCoordinates(dm));
4288:   }
4289:   /* Handle DMPlex refinement */
4290:   remap = PETSC_TRUE;
4291:   PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
4292:   PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4293:   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
4294:   if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4295:   if (refine && isHierarchy) {
4296:     DM *dms, coarseDM;

4298:     PetscCall(DMGetCoarseDM(dm, &coarseDM));
4299:     PetscCall(PetscObjectReference((PetscObject)coarseDM));
4300:     PetscCall(PetscMalloc1(refine, &dms));
4301:     PetscCall(DMRefineHierarchy(dm, refine, dms));
4302:     /* Total hack since we do not pass in a pointer */
4303:     PetscCall(DMPlexSwap_Static(dm, dms[refine - 1]));
4304:     if (refine == 1) {
4305:       PetscCall(DMSetCoarseDM(dm, dms[0]));
4306:       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4307:     } else {
4308:       PetscCall(DMSetCoarseDM(dm, dms[refine - 2]));
4309:       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4310:       PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1]));
4311:       PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE));
4312:     }
4313:     PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM));
4314:     PetscCall(PetscObjectDereference((PetscObject)coarseDM));
4315:     /* Free DMs */
4316:     for (r = 0; r < refine; ++r) {
4317:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4318:       PetscCall(DMDestroy(&dms[r]));
4319:     }
4320:     PetscCall(PetscFree(dms));
4321:   } else {
4322:     for (r = 0; r < refine; ++r) {
4323:       DM             rdm;
4324:       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4326:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4327:       PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4328:       /* Total hack since we do not pass in a pointer */
4329:       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4330:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4331:       if (coordFunc && remap) {
4332:         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4333:         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4334:       }
4335:     }
4336:   }
4337:   /* Handle DMPlex coarsening */
4338:   PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0));
4339:   PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0));
4340:   if (coarsen && isHierarchy) {
4341:     DM *dms;

4343:     PetscCall(PetscMalloc1(coarsen, &dms));
4344:     PetscCall(DMCoarsenHierarchy(dm, coarsen, dms));
4345:     /* Free DMs */
4346:     for (r = 0; r < coarsen; ++r) {
4347:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4348:       PetscCall(DMDestroy(&dms[r]));
4349:     }
4350:     PetscCall(PetscFree(dms));
4351:   } else {
4352:     for (r = 0; r < coarsen; ++r) {
4353:       DM             cdm;
4354:       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;

4356:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4357:       PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm));
4358:       /* Total hack since we do not pass in a pointer */
4359:       PetscCall(DMPlexReplace_Internal(dm, &cdm));
4360:       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4361:       if (coordFunc) {
4362:         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4363:         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4364:       }
4365:     }
4366:   }
4367:   /* Handle ghost cells */
4368:   PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL));
4369:   if (ghostCells) {
4370:     DM   gdm;
4371:     char lname[PETSC_MAX_PATH_LEN];

4373:     lname[0] = '\0';
4374:     PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg));
4375:     PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm));
4376:     PetscCall(DMPlexReplace_Internal(dm, &gdm));
4377:   }
4378:   /* Handle 1D order */
4379:   if (reorder != DMPLEX_REORDER_DEFAULT_FALSE && dim == 1) {
4380:     DM           cdm, rdm;
4381:     PetscDS      cds;
4382:     PetscObject  obj;
4383:     PetscClassId id = PETSC_OBJECT_CLASSID;
4384:     IS           perm;
4385:     PetscInt     Nf;
4386:     PetscBool    distributed;

4388:     PetscCall(DMPlexIsDistributed(dm, &distributed));
4389:     PetscCall(DMGetCoordinateDM(dm, &cdm));
4390:     PetscCall(DMGetDS(cdm, &cds));
4391:     PetscCall(PetscDSGetNumFields(cds, &Nf));
4392:     if (Nf) {
4393:       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4394:       PetscCall(PetscObjectGetClassId(obj, &id));
4395:     }
4396:     if (!distributed && id != PETSCFE_CLASSID) {
4397:       PetscCall(DMPlexGetOrdering1D(dm, &perm));
4398:       PetscCall(DMPlexPermute(dm, perm, &rdm));
4399:       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4400:       PetscCall(ISDestroy(&perm));
4401:     }
4402:   }
4403: /* Handle */
4404: non_refine:
4405:   PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4406:   PetscOptionsHeadEnd();
4407:   PetscFunctionReturn(PETSC_SUCCESS);
4408: }

4410: static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec)
4411: {
4412:   PetscFunctionBegin;
4413:   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
4414:   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
4415:   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex));
4416:   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native));
4417:   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex));
4418:   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native));
4419:   PetscFunctionReturn(PETSC_SUCCESS);
4420: }

4422: static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec)
4423: {
4424:   PetscFunctionBegin;
4425:   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
4426:   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local));
4427:   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local));
4428:   PetscFunctionReturn(PETSC_SUCCESS);
4429: }

4431: static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4432: {
4433:   PetscInt depth, d;

4435:   PetscFunctionBegin;
4436:   PetscCall(DMPlexGetDepth(dm, &depth));
4437:   if (depth == 1) {
4438:     PetscCall(DMGetDimension(dm, &d));
4439:     if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4440:     else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd));
4441:     else {
4442:       *pStart = 0;
4443:       *pEnd   = 0;
4444:     }
4445:   } else {
4446:     PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4447:   }
4448:   PetscFunctionReturn(PETSC_SUCCESS);
4449: }

4451: static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
4452: {
4453:   PetscSF            sf;
4454:   PetscInt           niranks, njranks, n;
4455:   const PetscMPIInt *iranks, *jranks;
4456:   DM_Plex           *data = (DM_Plex *)dm->data;

4458:   PetscFunctionBegin;
4459:   PetscCall(DMGetPointSF(dm, &sf));
4460:   if (!data->neighbors) {
4461:     PetscCall(PetscSFSetUp(sf));
4462:     PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL));
4463:     PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL));
4464:     PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors));
4465:     PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks));
4466:     PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks));
4467:     n = njranks + niranks;
4468:     PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1));
4469:     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
4470:     PetscCall(PetscMPIIntCast(n, data->neighbors));
4471:   }
4472:   if (nranks) *nranks = data->neighbors[0];
4473:   if (ranks) {
4474:     if (data->neighbors[0]) *ranks = data->neighbors + 1;
4475:     else *ranks = NULL;
4476:   }
4477:   PetscFunctionReturn(PETSC_SUCCESS);
4478: }

4480: PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec);

4482: static PetscErrorCode DMInitialize_Plex(DM dm)
4483: {
4484:   PetscFunctionBegin;
4485:   dm->ops->view                      = DMView_Plex;
4486:   dm->ops->load                      = DMLoad_Plex;
4487:   dm->ops->setfromoptions            = DMSetFromOptions_Plex;
4488:   dm->ops->clone                     = DMClone_Plex;
4489:   dm->ops->setup                     = DMSetUp_Plex;
4490:   dm->ops->createlocalsection        = DMCreateLocalSection_Plex;
4491:   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_Plex;
4492:   dm->ops->createglobalvector        = DMCreateGlobalVector_Plex;
4493:   dm->ops->createlocalvector         = DMCreateLocalVector_Plex;
4494:   dm->ops->getlocaltoglobalmapping   = NULL;
4495:   dm->ops->createfieldis             = NULL;
4496:   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_Plex;
4497:   dm->ops->createcoordinatefield     = DMCreateCoordinateField_Plex;
4498:   dm->ops->getcoloring               = NULL;
4499:   dm->ops->creatematrix              = DMCreateMatrix_Plex;
4500:   dm->ops->createinterpolation       = DMCreateInterpolation_Plex;
4501:   dm->ops->createmassmatrix          = DMCreateMassMatrix_Plex;
4502:   dm->ops->createmassmatrixlumped    = DMCreateMassMatrixLumped_Plex;
4503:   dm->ops->createinjection           = DMCreateInjection_Plex;
4504:   dm->ops->refine                    = DMRefine_Plex;
4505:   dm->ops->coarsen                   = DMCoarsen_Plex;
4506:   dm->ops->refinehierarchy           = DMRefineHierarchy_Plex;
4507:   dm->ops->coarsenhierarchy          = DMCoarsenHierarchy_Plex;
4508:   dm->ops->extrude                   = DMExtrude_Plex;
4509:   dm->ops->globaltolocalbegin        = NULL;
4510:   dm->ops->globaltolocalend          = NULL;
4511:   dm->ops->localtoglobalbegin        = NULL;
4512:   dm->ops->localtoglobalend          = NULL;
4513:   dm->ops->destroy                   = DMDestroy_Plex;
4514:   dm->ops->createsubdm               = DMCreateSubDM_Plex;
4515:   dm->ops->createsuperdm             = DMCreateSuperDM_Plex;
4516:   dm->ops->getdimpoints              = DMGetDimPoints_Plex;
4517:   dm->ops->locatepoints              = DMLocatePoints_Plex;
4518:   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_Plex;
4519:   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex;
4520:   dm->ops->projectfieldlocal         = DMProjectFieldLocal_Plex;
4521:   dm->ops->projectfieldlabellocal    = DMProjectFieldLabelLocal_Plex;
4522:   dm->ops->projectbdfieldlabellocal  = DMProjectBdFieldLabelLocal_Plex;
4523:   dm->ops->computel2diff             = DMComputeL2Diff_Plex;
4524:   dm->ops->computel2gradientdiff     = DMComputeL2GradientDiff_Plex;
4525:   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_Plex;
4526:   dm->ops->getneighbors              = DMGetNeighbors_Plex;
4527:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex));
4528:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex));
4529:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex));
4530:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex));
4531:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
4532:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex));
4533:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex));
4534:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex));
4535:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex));
4536:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex));
4537:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
4538:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex));
4539:   PetscFunctionReturn(PETSC_SUCCESS);
4540: }

4542: PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
4543: {
4544:   DM_Plex *mesh = (DM_Plex *)dm->data;
4545:   PetscSF  face_sf;

4547:   PetscFunctionBegin;
4548:   mesh->refct++;
4549:   (*newdm)->data = mesh;
4550:   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &face_sf));
4551:   PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, face_sf));
4552:   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX));
4553:   PetscCall(DMInitialize_Plex(*newdm));
4554:   PetscFunctionReturn(PETSC_SUCCESS);
4555: }

4557: /*MC
4558:   DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
4559:                     In the local representation, Vecs contain all unknowns in the interior and shared boundary. This is
4560:                     specified by a PetscSection object. Ownership in the global representation is determined by
4561:                     ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object.

4563:   Options Database Keys:
4564: + -dm_refine_pre                     - Refine mesh before distribution
4565: + -dm_refine_uniform_pre             - Choose uniform or generator-based refinement
4566: + -dm_refine_volume_limit_pre        - Cell volume limit after pre-refinement using generator
4567: . -dm_distribute                     - Distribute mesh across processes
4568: . -dm_distribute_overlap             - Number of cells to overlap for distribution
4569: . -dm_refine                         - Refine mesh after distribution
4570: . -dm_plex_hash_location             - Use grid hashing for point location
4571: . -dm_plex_hash_box_faces <n,m,p>    - The number of divisions in each direction of the grid hash
4572: . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
4573: . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
4574: . -dm_plex_max_projection_height     - Maximum mesh point height used to project locally
4575: . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
4576: . -dm_plex_check_all                 - Perform all shecks below
4577: . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
4578: . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
4579: . -dm_plex_check_faces <celltype>    - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
4580: . -dm_plex_check_geometry            - Check that cells have positive volume
4581: . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
4582: . -dm_plex_view_scale <num>          - Scale the TikZ
4583: - -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices

4585:   Level: intermediate

4587: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection`
4588: M*/

4590: PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
4591: {
4592:   DM_Plex *mesh;
4593:   PetscInt unit;

4595:   PetscFunctionBegin;
4597:   PetscCall(PetscNew(&mesh));
4598:   dm->data = mesh;

4600:   mesh->refct = 1;
4601:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection));
4602:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection));
4603:   mesh->refinementUniform      = PETSC_TRUE;
4604:   mesh->refinementLimit        = -1.0;
4605:   mesh->distDefault            = PETSC_TRUE;
4606:   mesh->reorderDefault         = DMPLEX_REORDER_DEFAULT_NOTSET;
4607:   mesh->distributionName       = NULL;
4608:   mesh->interpolated           = DMPLEX_INTERPOLATED_INVALID;
4609:   mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID;

4611:   PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner));
4612:   mesh->remeshBd = PETSC_FALSE;

4614:   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;

4616:   mesh->depthState    = -1;
4617:   mesh->celltypeState = -1;
4618:   mesh->printTol      = 1.0e-10;

4620:   PetscCall(DMInitialize_Plex(dm));
4621:   PetscFunctionReturn(PETSC_SUCCESS);
4622: }

4624: /*@
4625:   DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.

4627:   Collective

4629:   Input Parameter:
4630: . comm - The communicator for the `DMPLEX` object

4632:   Output Parameter:
4633: . mesh  - The `DMPLEX` object

4635:   Level: beginner

4637: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`
4638: @*/
4639: PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
4640: {
4641:   PetscFunctionBegin;
4643:   PetscCall(DMCreate(comm, mesh));
4644:   PetscCall(DMSetType(*mesh, DMPLEX));
4645:   PetscFunctionReturn(PETSC_SUCCESS);
4646: }

4648: /*@C
4649:   DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)

4651:   Collective on dm

4653:   Input Parameters:
4654: + dm - The `DM`
4655: . numCells - The number of cells owned by this process
4656: . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
4657: . NVertices - The global number of vertices, or `PETSC_DETERMINE`
4658: . numCorners - The number of vertices for each cell
4659: - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell

4661:   Output Parameters:
4662: + vertexSF - (Optional) `PetscSF` describing complete vertex ownership
4663: - verticesAdjSaved - (Optional) vertex adjacency array

4665:   Level: advanced

4667:   Notes:
4668:   Two triangles sharing a face
4669: .vb

4671:         2
4672:       / | \
4673:      /  |  \
4674:     /   |   \
4675:    0  0 | 1  3
4676:     \   |   /
4677:      \  |  /
4678:       \ | /
4679:         1
4680: .ve
4681: would have input
4682: .vb
4683:   numCells = 2, numVertices = 4
4684:   cells = [0 1 2  1 3 2]
4685: .ve
4686: which would result in the `DMPLEX`
4687: .vb

4689:         4
4690:       / | \
4691:      /  |  \
4692:     /   |   \
4693:    2  0 | 1  5
4694:     \   |   /
4695:      \  |  /
4696:       \ | /
4697:         3
4698: .ve

4700:   Vertices are implicitly numbered consecutively 0,...,NVertices.
4701:   Each rank owns a chunk of numVertices consecutive vertices.
4702:   If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout.
4703:   If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
4704:   If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks.

4706:   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.

4708:   Fortran Note:
4709:   Not currently supported in Fortran.

4711: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
4712:           `PetscSF`
4713: @*/
4714: PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved)
4715: {
4716:   PetscSF     sfPoint;
4717:   PetscLayout layout;
4718:   PetscInt    numVerticesAdj, *verticesAdj, *cones, c, p;

4720:   PetscFunctionBegin;
4722:   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
4723:   /* Get/check global number of vertices */
4724:   {
4725:     PetscInt       NVerticesInCells, i;
4726:     const PetscInt len = numCells * numCorners;

4728:     /* NVerticesInCells = max(cells) + 1 */
4729:     NVerticesInCells = PETSC_MIN_INT;
4730:     for (i = 0; i < len; i++)
4731:       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
4732:     ++NVerticesInCells;
4733:     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));

4735:     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
4736:     else
4737:       PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells);
4738:   }
4739:   /* Count locally unique vertices */
4740:   {
4741:     PetscHSetI vhash;
4742:     PetscInt   off = 0;

4744:     PetscCall(PetscHSetICreate(&vhash));
4745:     for (c = 0; c < numCells; ++c) {
4746:       for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p]));
4747:     }
4748:     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
4749:     if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
4750:     else verticesAdj = *verticesAdjSaved;
4751:     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
4752:     PetscCall(PetscHSetIDestroy(&vhash));
4753:     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
4754:   }
4755:   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
4756:   /* Create cones */
4757:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
4758:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
4759:   PetscCall(DMSetUp(dm));
4760:   PetscCall(DMPlexGetCones(dm, &cones));
4761:   for (c = 0; c < numCells; ++c) {
4762:     for (p = 0; p < numCorners; ++p) {
4763:       const PetscInt gv = cells[c * numCorners + p];
4764:       PetscInt       lv;

4766:       /* Positions within verticesAdj form 0-based local vertex numbering;
4767:          we need to shift it by numCells to get correct DAG points (cells go first) */
4768:       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
4769:       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
4770:       cones[c * numCorners + p] = lv + numCells;
4771:     }
4772:   }
4773:   /* Build point sf */
4774:   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
4775:   PetscCall(PetscLayoutSetSize(layout, NVertices));
4776:   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
4777:   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4778:   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
4779:   PetscCall(PetscLayoutDestroy(&layout));
4780:   if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj));
4781:   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
4782:   if (dm->sf) {
4783:     const char *prefix;

4785:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
4786:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
4787:   }
4788:   PetscCall(DMSetPointSF(dm, sfPoint));
4789:   PetscCall(PetscSFDestroy(&sfPoint));
4790:   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)(*vertexSF), "Vertex Ownership SF"));
4791:   /* Fill in the rest of the topology structure */
4792:   PetscCall(DMPlexSymmetrize(dm));
4793:   PetscCall(DMPlexStratify(dm));
4794:   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
4795:   PetscFunctionReturn(PETSC_SUCCESS);
4796: }

4798: /*@C
4799:   DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)

4801:   Collective on dm

4803:   Input Parameters:
4804: + dm - The `DM`
4805: . spaceDim - The spatial dimension used for coordinates
4806: . sfVert - `PetscSF` describing complete vertex ownership
4807: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

4809:   Level: advanced

4811:   Fortran Note:
4812:   Not currently supported in Fortran.

4814: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()`
4815: @*/
4816: PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
4817: {
4818:   PetscSection coordSection;
4819:   Vec          coordinates;
4820:   PetscScalar *coords;
4821:   PetscInt     numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;

4823:   PetscFunctionBegin;
4824:   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
4825:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
4826:   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
4827:   PetscCall(DMSetCoordinateDim(dm, spaceDim));
4828:   PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL));
4829:   PetscCheck(vEnd - vStart == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Supplied sfVert has wrong number of leaves = %" PetscInt_FMT " != %" PetscInt_FMT " = vEnd - vStart", numVerticesAdj, vEnd - vStart);
4830:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
4831:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
4832:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
4833:   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
4834:   for (v = vStart; v < vEnd; ++v) {
4835:     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
4836:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
4837:   }
4838:   PetscCall(PetscSectionSetUp(coordSection));
4839:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
4840:   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
4841:   PetscCall(VecSetBlockSize(coordinates, spaceDim));
4842:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
4843:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
4844:   PetscCall(VecSetType(coordinates, VECSTANDARD));
4845:   PetscCall(VecGetArray(coordinates, &coords));
4846:   {
4847:     MPI_Datatype coordtype;

4849:     /* Need a temp buffer for coords if we have complex/single */
4850:     PetscCallMPI(MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype));
4851:     PetscCallMPI(MPI_Type_commit(&coordtype));
4852: #if defined(PETSC_USE_COMPLEX)
4853:     {
4854:       PetscScalar *svertexCoords;
4855:       PetscInt     i;
4856:       PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords));
4857:       for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i];
4858:       PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
4859:       PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
4860:       PetscCall(PetscFree(svertexCoords));
4861:     }
4862: #else
4863:     PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
4864:     PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
4865: #endif
4866:     PetscCallMPI(MPI_Type_free(&coordtype));
4867:   }
4868:   PetscCall(VecRestoreArray(coordinates, &coords));
4869:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
4870:   PetscCall(VecDestroy(&coordinates));
4871:   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
4872:   PetscFunctionReturn(PETSC_SUCCESS);
4873: }

4875: /*@
4876:   DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output)

4878:   Collective

4880:   Input Parameters:
4881: + comm - The communicator
4882: . dim - The topological dimension of the mesh
4883: . numCells - The number of cells owned by this process
4884: . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`
4885: . NVertices - The global number of vertices, or `PETSC_DECIDE`
4886: . numCorners - The number of vertices for each cell
4887: . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
4888: . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
4889: . spaceDim - The spatial dimension used for coordinates
4890: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

4892:   Output Parameters:
4893: + dm - The `DM`
4894: . vertexSF - (Optional) `PetscSF` describing complete vertex ownership
4895: - verticesAdjSaved - (Optional) vertex adjacency array

4897:   Level: intermediate

4899:   Notes:
4900:   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
4901:   `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`

4903:   See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters.

4905:   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.

4907: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
4908: @*/
4909: PetscErrorCode DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PetscSF *vertexSF, PetscInt **verticesAdj, DM *dm)
4910: {
4911:   PetscSF sfVert;

4913:   PetscFunctionBegin;
4914:   PetscCall(DMCreate(comm, dm));
4915:   PetscCall(DMSetType(*dm, DMPLEX));
4918:   PetscCall(DMSetDimension(*dm, dim));
4919:   PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj));
4920:   if (interpolate) {
4921:     DM idm;

4923:     PetscCall(DMPlexInterpolate(*dm, &idm));
4924:     PetscCall(DMDestroy(dm));
4925:     *dm = idm;
4926:   }
4927:   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
4928:   if (vertexSF) *vertexSF = sfVert;
4929:   else PetscCall(PetscSFDestroy(&sfVert));
4930:   PetscFunctionReturn(PETSC_SUCCESS);
4931: }

4933: /*@C
4934:   DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)

4936:   Collective on dm

4938:   Input Parameters:
4939: + dm - The `DM`
4940: . numCells - The number of cells owned by this process
4941: . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE`
4942: . numCorners - The number of vertices for each cell
4943: - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell

4945:   Level: advanced

4947:   Notes:
4948:   Two triangles sharing a face
4949: .vb

4951:         2
4952:       / | \
4953:      /  |  \
4954:     /   |   \
4955:    0  0 | 1  3
4956:     \   |   /
4957:      \  |  /
4958:       \ | /
4959:         1
4960: .ve
4961: would have input
4962: .vb
4963:   numCells = 2, numVertices = 4
4964:   cells = [0 1 2  1 3 2]
4965: .ve
4966: which would result in the `DMPLEX`
4967: .vb

4969:         4
4970:       / | \
4971:      /  |  \
4972:     /   |   \
4973:    2  0 | 1  5
4974:     \   |   /
4975:      \  |  /
4976:       \ | /
4977:         3
4978: .ve

4980:   If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1.

4982:   Not currently supported in Fortran.

4984: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()`
4985: @*/
4986: PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
4987: {
4988:   PetscInt *cones, c, p, dim;

4990:   PetscFunctionBegin;
4991:   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
4992:   PetscCall(DMGetDimension(dm, &dim));
4993:   /* Get/check global number of vertices */
4994:   {
4995:     PetscInt       NVerticesInCells, i;
4996:     const PetscInt len = numCells * numCorners;

4998:     /* NVerticesInCells = max(cells) + 1 */
4999:     NVerticesInCells = PETSC_MIN_INT;
5000:     for (i = 0; i < len; i++)
5001:       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5002:     ++NVerticesInCells;

5004:     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
5005:     else
5006:       PetscCheck(numVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, numVertices, NVerticesInCells);
5007:   }
5008:   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
5009:   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
5010:   PetscCall(DMSetUp(dm));
5011:   PetscCall(DMPlexGetCones(dm, &cones));
5012:   for (c = 0; c < numCells; ++c) {
5013:     for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells;
5014:   }
5015:   PetscCall(DMPlexSymmetrize(dm));
5016:   PetscCall(DMPlexStratify(dm));
5017:   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5018:   PetscFunctionReturn(PETSC_SUCCESS);
5019: }

5021: /*@C
5022:   DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)

5024:   Collective on dm

5026:   Input Parameters:
5027: + dm - The `DM`
5028: . spaceDim - The spatial dimension used for coordinates
5029: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex

5031:   Level: advanced

5033:   Fortran Note:
5034:   Not currently supported in Fortran.

5036: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()`
5037: @*/
5038: PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
5039: {
5040:   PetscSection coordSection;
5041:   Vec          coordinates;
5042:   DM           cdm;
5043:   PetscScalar *coords;
5044:   PetscInt     v, vStart, vEnd, d;

5046:   PetscFunctionBegin;
5047:   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5048:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5049:   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
5050:   PetscCall(DMSetCoordinateDim(dm, spaceDim));
5051:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5052:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5053:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
5054:   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
5055:   for (v = vStart; v < vEnd; ++v) {
5056:     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
5057:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
5058:   }
5059:   PetscCall(PetscSectionSetUp(coordSection));

5061:   PetscCall(DMGetCoordinateDM(dm, &cdm));
5062:   PetscCall(DMCreateLocalVector(cdm, &coordinates));
5063:   PetscCall(VecSetBlockSize(coordinates, spaceDim));
5064:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5065:   PetscCall(VecGetArrayWrite(coordinates, &coords));
5066:   for (v = 0; v < vEnd - vStart; ++v) {
5067:     for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d];
5068:   }
5069:   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5070:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5071:   PetscCall(VecDestroy(&coordinates));
5072:   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5073:   PetscFunctionReturn(PETSC_SUCCESS);
5074: }

5076: /*@
5077:   DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input

5079:   Collective

5081:   Input Parameters:
5082: + comm - The communicator
5083: . dim - The topological dimension of the mesh
5084: . numCells - The number of cells, only on process 0
5085: . numVertices - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0
5086: . numCorners - The number of vertices for each cell, only on process 0
5087: . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
5088: . cells - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0
5089: . spaceDim - The spatial dimension used for coordinates
5090: - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0

5092:   Output Parameter:
5093: . dm - The `DM`, which only has points on process 0

5095:   Level: intermediate

5097:   Notes:
5098:   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`,
5099:   `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()`

5101:   See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters.
5102:   See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters.
5103:   See `DMPlexCreateFromCellListParallelPetsc()` for parallel input

5105: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
5106: @*/
5107: PetscErrorCode DMPlexCreateFromCellListPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], DM *dm)
5108: {
5109:   PetscMPIInt rank;

5111:   PetscFunctionBegin;
5112:   PetscCheck(dim, comm, PETSC_ERR_ARG_OUTOFRANGE, "This is not appropriate for 0-dimensional meshes. Consider either creating the DM using DMPlexCreateFromDAG(), by hand, or using DMSwarm.");
5113:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5114:   PetscCall(DMCreate(comm, dm));
5115:   PetscCall(DMSetType(*dm, DMPLEX));
5116:   PetscCall(DMSetDimension(*dm, dim));
5117:   if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells));
5118:   else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL));
5119:   if (interpolate) {
5120:     DM idm;

5122:     PetscCall(DMPlexInterpolate(*dm, &idm));
5123:     PetscCall(DMDestroy(dm));
5124:     *dm = idm;
5125:   }
5126:   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords));
5127:   else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL));
5128:   PetscFunctionReturn(PETSC_SUCCESS);
5129: }

5131: /*@
5132:   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a DM

5134:   Input Parameters:
5135: + dm - The empty DM object, usually from DMCreate() and DMSetDimension()
5136: . depth - The depth of the DAG
5137: . numPoints - Array of size depth + 1 containing the number of points at each depth
5138: . coneSize - The cone size of each point
5139: . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
5140: . coneOrientations - The orientation of each cone point
5141: - vertexCoords - An array of numPoints[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via DMSetCoordinateDim()

5143:   Output Parameter:
5144: . dm - The DM

5146:   Note:
5147:   Two triangles sharing a face would have input
5148: .vb
5149:   depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
5150:   cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
5151:  vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
5152: .ve
5153: which would result in the DMPlex
5154: .vb
5155:         4
5156:       / | \
5157:      /  |  \
5158:     /   |   \
5159:    2  0 | 1  5
5160:     \   |   /
5161:      \  |  /
5162:       \ | /
5163:         3
5164: .ve
5165:  Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()`

5167:   Level: advanced

5169: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5170: @*/
5171: PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
5172: {
5173:   Vec          coordinates;
5174:   PetscSection coordSection;
5175:   PetscScalar *coords;
5176:   PetscInt     coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;

5178:   PetscFunctionBegin;
5179:   PetscCall(DMGetDimension(dm, &dim));
5180:   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
5181:   PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim);
5182:   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
5183:   PetscCall(DMPlexSetChart(dm, pStart, pEnd));
5184:   for (p = pStart; p < pEnd; ++p) {
5185:     PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart]));
5186:     if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart;
5187:   }
5188:   PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]);
5189:   PetscCall(DMSetUp(dm)); /* Allocate space for cones */
5190:   for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) {
5191:     PetscCall(DMPlexSetCone(dm, p, &cones[off]));
5192:     PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off]));
5193:   }
5194:   PetscCall(DMPlexSymmetrize(dm));
5195:   PetscCall(DMPlexStratify(dm));
5196:   /* Build coordinates */
5197:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5198:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5199:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed));
5200:   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0]));
5201:   for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) {
5202:     PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed));
5203:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed));
5204:   }
5205:   PetscCall(PetscSectionSetUp(coordSection));
5206:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5207:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5208:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5209:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5210:   PetscCall(VecSetBlockSize(coordinates, dimEmbed));
5211:   PetscCall(VecSetType(coordinates, VECSTANDARD));
5212:   if (vertexCoords) {
5213:     PetscCall(VecGetArray(coordinates, &coords));
5214:     for (v = 0; v < numPoints[0]; ++v) {
5215:       PetscInt off;

5217:       PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off));
5218:       for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d];
5219:     }
5220:   }
5221:   PetscCall(VecRestoreArray(coordinates, &coords));
5222:   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5223:   PetscCall(VecDestroy(&coordinates));
5224:   PetscFunctionReturn(PETSC_SUCCESS);
5225: }

5227: /*@C
5228:   DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file.

5230:   Collective

5232: + comm        - The MPI communicator
5233: . filename    - Name of the .dat file
5234: - interpolate - Create faces and edges in the mesh

5236:   Output Parameter:
5237: . dm  - The `DM` object representing the mesh

5239:   Level: beginner

5241:   Note:
5242:   The format is the simplest possible:
5243: .vb
5244:   Ne
5245:   v0 v1 ... vk
5246:   Nv
5247:   x y z marker
5248: .ve

5250:   Developer Note:
5251:   Should use a `PetscViewer` not a filename

5253: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateMedFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
5254: @*/
5255: static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
5256: {
5257:   DMLabel      marker;
5258:   PetscViewer  viewer;
5259:   Vec          coordinates;
5260:   PetscSection coordSection;
5261:   PetscScalar *coords;
5262:   char         line[PETSC_MAX_PATH_LEN];
5263:   PetscInt     dim = 3, cdim = 3, coordSize, v, c, d;
5264:   PetscMPIInt  rank;
5265:   int          snum, Nv, Nc, Ncn, Nl;

5267:   PetscFunctionBegin;
5268:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5269:   PetscCall(PetscViewerCreate(comm, &viewer));
5270:   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
5271:   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5272:   PetscCall(PetscViewerFileSetName(viewer, filename));
5273:   if (rank == 0) {
5274:     PetscCall(PetscViewerRead(viewer, line, 4, NULL, PETSC_STRING));
5275:     snum = sscanf(line, "%d %d %d %d", &Nc, &Nv, &Ncn, &Nl);
5276:     PetscCheck(snum == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5277:   } else {
5278:     Nc = Nv = Ncn = Nl = 0;
5279:   }
5280:   PetscCall(DMCreate(comm, dm));
5281:   PetscCall(DMSetType(*dm, DMPLEX));
5282:   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
5283:   PetscCall(DMSetDimension(*dm, dim));
5284:   PetscCall(DMSetCoordinateDim(*dm, cdim));
5285:   /* Read topology */
5286:   if (rank == 0) {
5287:     char     format[PETSC_MAX_PATH_LEN];
5288:     PetscInt cone[8];
5289:     int      vbuf[8], v;

5291:     for (c = 0; c < Ncn; ++c) {
5292:       format[c * 3 + 0] = '%';
5293:       format[c * 3 + 1] = 'd';
5294:       format[c * 3 + 2] = ' ';
5295:     }
5296:     format[Ncn * 3 - 1] = '\0';
5297:     for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn));
5298:     PetscCall(DMSetUp(*dm));
5299:     for (c = 0; c < Nc; ++c) {
5300:       PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING));
5301:       switch (Ncn) {
5302:       case 2:
5303:         snum = sscanf(line, format, &vbuf[0], &vbuf[1]);
5304:         break;
5305:       case 3:
5306:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]);
5307:         break;
5308:       case 4:
5309:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]);
5310:         break;
5311:       case 6:
5312:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]);
5313:         break;
5314:       case 8:
5315:         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
5316:         break;
5317:       default:
5318:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn);
5319:       }
5320:       PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5321:       for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc;
5322:       /* Hexahedra are inverted */
5323:       if (Ncn == 8) {
5324:         PetscInt tmp = cone[1];
5325:         cone[1]      = cone[3];
5326:         cone[3]      = tmp;
5327:       }
5328:       PetscCall(DMPlexSetCone(*dm, c, cone));
5329:     }
5330:   }
5331:   PetscCall(DMPlexSymmetrize(*dm));
5332:   PetscCall(DMPlexStratify(*dm));
5333:   /* Read coordinates */
5334:   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
5335:   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5336:   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
5337:   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
5338:   for (v = Nc; v < Nc + Nv; ++v) {
5339:     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
5340:     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
5341:   }
5342:   PetscCall(PetscSectionSetUp(coordSection));
5343:   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5344:   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5345:   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5346:   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5347:   PetscCall(VecSetBlockSize(coordinates, cdim));
5348:   PetscCall(VecSetType(coordinates, VECSTANDARD));
5349:   PetscCall(VecGetArray(coordinates, &coords));
5350:   if (rank == 0) {
5351:     char   format[PETSC_MAX_PATH_LEN];
5352:     double x[3];
5353:     int    l, val[3];

5355:     if (Nl) {
5356:       for (l = 0; l < Nl; ++l) {
5357:         format[l * 3 + 0] = '%';
5358:         format[l * 3 + 1] = 'd';
5359:         format[l * 3 + 2] = ' ';
5360:       }
5361:       format[Nl * 3 - 1] = '\0';
5362:       PetscCall(DMCreateLabel(*dm, "marker"));
5363:       PetscCall(DMGetLabel(*dm, "marker", &marker));
5364:     }
5365:     for (v = 0; v < Nv; ++v) {
5366:       PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING));
5367:       snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]);
5368:       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5369:       switch (Nl) {
5370:       case 0:
5371:         snum = 0;
5372:         break;
5373:       case 1:
5374:         snum = sscanf(line, format, &val[0]);
5375:         break;
5376:       case 2:
5377:         snum = sscanf(line, format, &val[0], &val[1]);
5378:         break;
5379:       case 3:
5380:         snum = sscanf(line, format, &val[0], &val[1], &val[2]);
5381:         break;
5382:       default:
5383:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl);
5384:       }
5385:       PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5386:       for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d];
5387:       for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l]));
5388:     }
5389:   }
5390:   PetscCall(VecRestoreArray(coordinates, &coords));
5391:   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
5392:   PetscCall(VecDestroy(&coordinates));
5393:   PetscCall(PetscViewerDestroy(&viewer));
5394:   if (interpolate) {
5395:     DM      idm;
5396:     DMLabel bdlabel;

5398:     PetscCall(DMPlexInterpolate(*dm, &idm));
5399:     PetscCall(DMDestroy(dm));
5400:     *dm = idm;

5402:     if (!Nl) {
5403:       PetscCall(DMCreateLabel(*dm, "marker"));
5404:       PetscCall(DMGetLabel(*dm, "marker", &bdlabel));
5405:       PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel));
5406:       PetscCall(DMPlexLabelComplete(*dm, bdlabel));
5407:     }
5408:   }
5409:   PetscFunctionReturn(PETSC_SUCCESS);
5410: }

5412: /*@C
5413:   DMPlexCreateFromFile - This takes a filename and produces a `DM`

5415:   Collective

5417:   Input Parameters:
5418: + comm - The communicator
5419: . filename - A file name
5420: . plexname - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats
5421: - interpolate - Flag to create intermediate mesh pieces (edges, faces)

5423:   Output Parameter:
5424: . dm - The `DM`

5426:   Options Database Key:
5427: . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5

5429:   Use -dm_plex_create_ prefix to pass options to the internal PetscViewer, e.g.
5430: $ -dm_plex_create_viewer_hdf5_collective

5432:   Level: beginner

5434:   Notes:
5435:   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
5436:   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
5437:   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
5438:   The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally
5439:   calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats.

5441: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()`
5442: @*/
5443: PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm)
5444: {
5445:   const char  extGmsh[]      = ".msh";
5446:   const char  extGmsh2[]     = ".msh2";
5447:   const char  extGmsh4[]     = ".msh4";
5448:   const char  extCGNS[]      = ".cgns";
5449:   const char  extExodus[]    = ".exo";
5450:   const char  extExodus_e[]  = ".e";
5451:   const char  extGenesis[]   = ".gen";
5452:   const char  extFluent[]    = ".cas";
5453:   const char  extHDF5[]      = ".h5";
5454:   const char  extMed[]       = ".med";
5455:   const char  extPLY[]       = ".ply";
5456:   const char  extEGADSLite[] = ".egadslite";
5457:   const char  extEGADS[]     = ".egads";
5458:   const char  extIGES[]      = ".igs";
5459:   const char  extSTEP[]      = ".stp";
5460:   const char  extCV[]        = ".dat";
5461:   size_t      len;
5462:   PetscBool   isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isMed, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV;
5463:   PetscMPIInt rank;

5465:   PetscFunctionBegin;
5469:   PetscCall(DMInitializePackage());
5470:   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5471:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5472:   PetscCall(PetscStrlen(filename, &len));
5473:   PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");

5475: #define CheckExtension(extension__, is_extension__) \
5476:   do { \
5477:     PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \
5478:     /* don't count the null-terminator at the end */ \
5479:     const size_t ext_len = sizeof(extension__) - 1; \
5480:     if (len < ext_len) { \
5481:       is_extension__ = PETSC_FALSE; \
5482:     } else { \
5483:       PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \
5484:     } \
5485:   } while (0)

5487:   CheckExtension(extGmsh, isGmsh);
5488:   CheckExtension(extGmsh2, isGmsh2);
5489:   CheckExtension(extGmsh4, isGmsh4);
5490:   CheckExtension(extCGNS, isCGNS);
5491:   CheckExtension(extExodus, isExodus);
5492:   if (!isExodus) CheckExtension(extExodus_e, isExodus);
5493:   CheckExtension(extGenesis, isGenesis);
5494:   CheckExtension(extFluent, isFluent);
5495:   CheckExtension(extHDF5, isHDF5);
5496:   CheckExtension(extMed, isMed);
5497:   CheckExtension(extPLY, isPLY);
5498:   CheckExtension(extEGADSLite, isEGADSLite);
5499:   CheckExtension(extEGADS, isEGADS);
5500:   CheckExtension(extIGES, isIGES);
5501:   CheckExtension(extSTEP, isSTEP);
5502:   CheckExtension(extCV, isCV);

5504: #undef CheckExtension

5506:   if (isGmsh || isGmsh2 || isGmsh4) {
5507:     PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm));
5508:   } else if (isCGNS) {
5509:     PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm));
5510:   } else if (isExodus || isGenesis) {
5511:     PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm));
5512:   } else if (isFluent) {
5513:     PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm));
5514:   } else if (isHDF5) {
5515:     PetscBool   load_hdf5_xdmf = PETSC_FALSE;
5516:     PetscViewer viewer;

5518:     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
5519:     PetscCall(PetscStrncmp(&filename[PetscMax(0, len - 8)], ".xdmf", 5, &load_hdf5_xdmf));
5520:     PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &load_hdf5_xdmf, NULL));
5521:     PetscCall(PetscViewerCreate(comm, &viewer));
5522:     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5));
5523:     PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_"));
5524:     PetscCall(PetscViewerSetFromOptions(viewer));
5525:     PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5526:     PetscCall(PetscViewerFileSetName(viewer, filename));

5528:     PetscCall(DMCreate(comm, dm));
5529:     PetscCall(PetscObjectSetName((PetscObject)(*dm), plexname));
5530:     PetscCall(DMSetType(*dm, DMPLEX));
5531:     if (load_hdf5_xdmf) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF));
5532:     PetscCall(DMLoad(*dm, viewer));
5533:     if (load_hdf5_xdmf) PetscCall(PetscViewerPopFormat(viewer));
5534:     PetscCall(PetscViewerDestroy(&viewer));

5536:     if (interpolate) {
5537:       DM idm;

5539:       PetscCall(DMPlexInterpolate(*dm, &idm));
5540:       PetscCall(DMDestroy(dm));
5541:       *dm = idm;
5542:     }
5543:   } else if (isMed) {
5544:     PetscCall(DMPlexCreateMedFromFile(comm, filename, interpolate, dm));
5545:   } else if (isPLY) {
5546:     PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm));
5547:   } else if (isEGADSLite || isEGADS || isIGES || isSTEP) {
5548:     if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm));
5549:     else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm));
5550:     if (!interpolate) {
5551:       DM udm;

5553:       PetscCall(DMPlexUninterpolate(*dm, &udm));
5554:       PetscCall(DMDestroy(dm));
5555:       *dm = udm;
5556:     }
5557:   } else if (isCV) {
5558:     PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm));
5559:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
5560:   PetscCall(PetscStrlen(plexname, &len));
5561:   if (len) PetscCall(PetscObjectSetName((PetscObject)(*dm), plexname));
5562:   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5563:   PetscFunctionReturn(PETSC_SUCCESS);
5564: }
5565: /*@C
5566:   DMPlexCreateEphemeral - This takes a `DMPlexTransform` and a base `DMPlex` and produces an ephemeral `DM`, meaning one that is created on the fly in response to queries.

5568:   Input Parameter:
5569: . tr - The `DMPlexTransform`

5571:   Output Parameter:
5572: . dm - The `DM`

5574:   Notes:
5575:   An emphemeral mesh is one that is not stored concretely, as in the default Plex implementation, but rather is produced on the fly in response to queries, using information from the transform and the base mesh.

5577:   Level: beginner

5579: .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5580: @*/
5581: PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, DM *dm)
5582: {
5583:   DM       bdm;
5584:   PetscInt Nl;

5586:   PetscFunctionBegin;
5587:   PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm));
5588:   PetscCall(DMSetType(*dm, DMPLEX));
5589:   PetscCall(DMSetFromOptions(*dm));

5591:   PetscCall(PetscObjectReference((PetscObject)tr));
5592:   PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr));
5593:   ((DM_Plex *)(*dm)->data)->tr = tr;

5595:   PetscCall(DMPlexTransformGetDM(tr, &bdm));
5596:   PetscCall(DMGetNumLabels(bdm, &Nl));
5597:   for (PetscInt l = 0; l < Nl; ++l) {
5598:     DMLabel     label, labelNew;
5599:     const char *lname;
5600:     PetscBool   isDepth, isCellType;

5602:     PetscCall(DMGetLabelName(bdm, l, &lname));
5603:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
5604:     if (isDepth) continue;
5605:     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
5606:     if (isCellType) continue;
5607:     PetscCall(DMCreateLabel(*dm, lname));
5608:     PetscCall(DMGetLabel(bdm, lname, &label));
5609:     PetscCall(DMGetLabel(*dm, lname, &labelNew));
5610:     PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL));
5611:     PetscCall(DMLabelEphemeralSetLabel(labelNew, label));
5612:     PetscCall(DMLabelEphemeralSetTransform(labelNew, tr));
5613:     PetscCall(DMLabelSetUp(labelNew));
5614:   }
5615:   PetscFunctionReturn(PETSC_SUCCESS);
5616: }