xref: /petsc/src/dm/impls/plex/plexcreate.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
3 #include <petsc/private/hashseti.h>   /*I   "petscdmplex.h"   I*/
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>
9 
10 #ifdef PETSC_HAVE_UNISTD_H
11   #include <unistd.h>
12 #endif
13 #include <errno.h>
14 
15 PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;
16 
17 /* External function declarations here */
18 static PetscErrorCode DMInitialize_Plex(DM dm);
19 
20 /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */
21 PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout)
22 {
23   const PetscReal     *maxCell, *Lstart, *L;
24   VecType              vecType;
25   MatType              matType;
26   PetscBool            dist, useCeed;
27   DMReorderDefaultFlag reorder;
28 
29   PetscFunctionBegin;
30   PetscCall(DMGetVecType(dmin, &vecType));
31   PetscCall(DMSetVecType(dmout, vecType));
32   PetscCall(DMGetMatType(dmin, &matType));
33   PetscCall(DMSetMatType(dmout, matType));
34   if (copyPeriodicity) {
35     PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L));
36     PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L));
37   }
38   PetscCall(DMPlexDistributeGetDefault(dmin, &dist));
39   PetscCall(DMPlexDistributeSetDefault(dmout, dist));
40   PetscCall(DMPlexReorderGetDefault(dmin, &reorder));
41   PetscCall(DMPlexReorderSetDefault(dmout, reorder));
42   PetscCall(DMPlexGetUseCeed(dmin, &useCeed));
43   PetscCall(DMPlexSetUseCeed(dmout, useCeed));
44   ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation;
45   ((DM_Plex *)dmout->data)->printSetValues  = ((DM_Plex *)dmin->data)->printSetValues;
46   ((DM_Plex *)dmout->data)->printFEM        = ((DM_Plex *)dmin->data)->printFEM;
47   ((DM_Plex *)dmout->data)->printFVM        = ((DM_Plex *)dmin->data)->printFVM;
48   ((DM_Plex *)dmout->data)->printL2         = ((DM_Plex *)dmin->data)->printL2;
49   ((DM_Plex *)dmout->data)->printLocate     = ((DM_Plex *)dmin->data)->printLocate;
50   ((DM_Plex *)dmout->data)->printTol        = ((DM_Plex *)dmin->data)->printTol;
51   if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0));
52   PetscFunctionReturn(PETSC_SUCCESS);
53 }
54 
55 /* Replace dm with the contents of ndm, and then destroy ndm
56    - Share the DM_Plex structure
57    - Share the coordinates
58    - Share the SF
59 */
60 PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm)
61 {
62   PetscSF          sf;
63   DM               dmNew = *ndm, coordDM, coarseDM;
64   Vec              coords;
65   const PetscReal *maxCell, *Lstart, *L;
66   PetscInt         dim, cdim;
67 
68   PetscFunctionBegin;
69   if (dm == dmNew) {
70     PetscCall(DMDestroy(ndm));
71     PetscFunctionReturn(PETSC_SUCCESS);
72   }
73   dm->setupcalled = dmNew->setupcalled;
74   if (!dm->hdr.name) {
75     const char *name;
76 
77     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
78     PetscCall(PetscObjectSetName((PetscObject)dm, name));
79   }
80   PetscCall(DMGetDimension(dmNew, &dim));
81   PetscCall(DMSetDimension(dm, dim));
82   PetscCall(DMGetCoordinateDim(dmNew, &cdim));
83   PetscCall(DMSetCoordinateDim(dm, cdim));
84   PetscCall(DMGetPointSF(dmNew, &sf));
85   PetscCall(DMSetPointSF(dm, sf));
86   PetscCall(DMGetCoordinateDM(dmNew, &coordDM));
87   PetscCall(DMGetCoordinatesLocal(dmNew, &coords));
88   PetscCall(DMSetCoordinateDM(dm, coordDM));
89   PetscCall(DMSetCoordinatesLocal(dm, coords));
90   PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM));
91   PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords));
92   PetscCall(DMSetCellCoordinateDM(dm, coordDM));
93   PetscCall(DMSetCellCoordinatesLocal(dm, coords));
94   /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */
95   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
96   dm->coordinates[0].field            = dmNew->coordinates[0].field;
97   ((DM_Plex *)dmNew->data)->coordFunc = ((DM_Plex *)dm->data)->coordFunc;
98   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
99   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
100   PetscCall(DMPlexGetGlobalToNaturalSF(dmNew, &sf));
101   PetscCall(DMPlexSetGlobalToNaturalSF(dm, sf));
102   PetscCall(DMDestroy_Plex(dm));
103   PetscCall(DMInitialize_Plex(dm));
104   dm->data = dmNew->data;
105   ((DM_Plex *)dmNew->data)->refct++;
106   {
107     PetscInt       num_face_sfs;
108     const PetscSF *sfs;
109     PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &sfs));
110     PetscCall(DMPlexSetIsoperiodicFaceSF(dm, num_face_sfs, (PetscSF *)sfs)); // for the compose function effect on dm
111   }
112   PetscCall(DMDestroyLabelLinkList_Internal(dm));
113   PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
114   PetscCall(DMGetCoarseDM(dmNew, &coarseDM));
115   PetscCall(DMSetCoarseDM(dm, coarseDM));
116   PetscCall(DMDestroy(ndm));
117   PetscFunctionReturn(PETSC_SUCCESS);
118 }
119 
120 /* Swap dm with the contents of dmNew
121    - Swap the DM_Plex structure
122    - Swap the coordinates
123    - Swap the point PetscSF
124 */
125 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
126 {
127   DM          coordDMA, coordDMB;
128   Vec         coordsA, coordsB;
129   PetscSF     sfA, sfB;
130   DMField     fieldTmp;
131   void       *tmp;
132   DMLabelLink listTmp;
133   DMLabel     depthTmp;
134   PetscInt    tmpI;
135 
136   PetscFunctionBegin;
137   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
138   PetscCall(DMGetPointSF(dmA, &sfA));
139   PetscCall(DMGetPointSF(dmB, &sfB));
140   PetscCall(PetscObjectReference((PetscObject)sfA));
141   PetscCall(DMSetPointSF(dmA, sfB));
142   PetscCall(DMSetPointSF(dmB, sfA));
143   PetscCall(PetscObjectDereference((PetscObject)sfA));
144 
145   PetscCall(DMGetCoordinateDM(dmA, &coordDMA));
146   PetscCall(DMGetCoordinateDM(dmB, &coordDMB));
147   PetscCall(PetscObjectReference((PetscObject)coordDMA));
148   PetscCall(DMSetCoordinateDM(dmA, coordDMB));
149   PetscCall(DMSetCoordinateDM(dmB, coordDMA));
150   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
151 
152   PetscCall(DMGetCoordinatesLocal(dmA, &coordsA));
153   PetscCall(DMGetCoordinatesLocal(dmB, &coordsB));
154   PetscCall(PetscObjectReference((PetscObject)coordsA));
155   PetscCall(DMSetCoordinatesLocal(dmA, coordsB));
156   PetscCall(DMSetCoordinatesLocal(dmB, coordsA));
157   PetscCall(PetscObjectDereference((PetscObject)coordsA));
158 
159   PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA));
160   PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB));
161   PetscCall(PetscObjectReference((PetscObject)coordDMA));
162   PetscCall(DMSetCellCoordinateDM(dmA, coordDMB));
163   PetscCall(DMSetCellCoordinateDM(dmB, coordDMA));
164   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
165 
166   PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA));
167   PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB));
168   PetscCall(PetscObjectReference((PetscObject)coordsA));
169   PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB));
170   PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA));
171   PetscCall(PetscObjectDereference((PetscObject)coordsA));
172 
173   fieldTmp                  = dmA->coordinates[0].field;
174   dmA->coordinates[0].field = dmB->coordinates[0].field;
175   dmB->coordinates[0].field = fieldTmp;
176   fieldTmp                  = dmA->coordinates[1].field;
177   dmA->coordinates[1].field = dmB->coordinates[1].field;
178   dmB->coordinates[1].field = fieldTmp;
179   tmp                       = dmA->data;
180   dmA->data                 = dmB->data;
181   dmB->data                 = tmp;
182   listTmp                   = dmA->labels;
183   dmA->labels               = dmB->labels;
184   dmB->labels               = listTmp;
185   depthTmp                  = dmA->depthLabel;
186   dmA->depthLabel           = dmB->depthLabel;
187   dmB->depthLabel           = depthTmp;
188   depthTmp                  = dmA->celltypeLabel;
189   dmA->celltypeLabel        = dmB->celltypeLabel;
190   dmB->celltypeLabel        = depthTmp;
191   tmpI                      = dmA->levelup;
192   dmA->levelup              = dmB->levelup;
193   dmB->levelup              = tmpI;
194   PetscFunctionReturn(PETSC_SUCCESS);
195 }
196 
197 PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm)
198 {
199   DM idm;
200 
201   PetscFunctionBegin;
202   PetscCall(DMPlexInterpolate(dm, &idm));
203   PetscCall(DMPlexCopyCoordinates(dm, idm));
204   PetscCall(DMPlexReplace_Internal(dm, &idm));
205   PetscFunctionReturn(PETSC_SUCCESS);
206 }
207 
208 /*@C
209   DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates
210 
211   Collective
212 
213   Input Parameters:
214 + dm        - The `DMPLEX`
215 . degree    - The degree of the finite element or `PETSC_DECIDE`
216 . project   - Flag to project current coordinates into the space
217 - coordFunc - An optional function to map new points from refinement to the surface
218 
219   Level: advanced
220 
221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFunc`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()`
222 @*/
223 PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool project, PetscPointFunc coordFunc)
224 {
225   DM_Plex *mesh = (DM_Plex *)dm->data;
226   PetscFE  fe   = NULL;
227   DM       cdm;
228   PetscInt dim, dE, qorder, height;
229 
230   PetscFunctionBegin;
231   PetscCall(DMGetDimension(dm, &dim));
232   PetscCall(DMGetCoordinateDim(dm, &dE));
233   qorder = degree;
234   PetscCall(DMGetCoordinateDM(dm, &cdm));
235   PetscObjectOptionsBegin((PetscObject)cdm);
236   PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0));
237   PetscOptionsEnd();
238   PetscCall(DMPlexGetVTKCellHeight(dm, &height));
239   if (degree >= 0) {
240     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
241     PetscInt       cStart, cEnd, gct;
242 
243     PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
244     if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct));
245     gct = (PetscInt)ct;
246     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm)));
247     ct = (DMPolytopeType)gct;
248     // Work around current bug in PetscDualSpaceSetUp_Lagrange()
249     //   Can be seen in plex_tutorials-ex10_1
250     if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe));
251   }
252   PetscCall(DMSetCoordinateDisc(dm, fe, project));
253   PetscCall(PetscFEDestroy(&fe));
254   mesh->coordFunc = coordFunc;
255   PetscFunctionReturn(PETSC_SUCCESS);
256 }
257 
258 /*@
259   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.
260 
261   Collective
262 
263   Input Parameters:
264 + comm            - The communicator for the `DM` object
265 . dim             - The spatial dimension
266 . simplex         - Flag for simplicial cells, otherwise they are tensor product cells
267 . interpolate     - Flag to create intermediate mesh pieces (edges, faces)
268 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell
269 
270   Output Parameter:
271 . newdm - The `DM` object
272 
273   Level: beginner
274 
275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()`
276 @*/
277 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm)
278 {
279   DM          dm;
280   PetscMPIInt rank;
281 
282   PetscFunctionBegin;
283   PetscCall(DMCreate(comm, &dm));
284   PetscCall(DMSetType(dm, DMPLEX));
285   PetscCall(DMSetDimension(dm, dim));
286   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
287   PetscCallMPI(MPI_Comm_rank(comm, &rank));
288   switch (dim) {
289   case 2:
290     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular"));
291     else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral"));
292     break;
293   case 3:
294     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral"));
295     else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral"));
296     break;
297   default:
298     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
299   }
300   if (rank) {
301     PetscInt numPoints[2] = {0, 0};
302     PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL));
303   } else {
304     switch (dim) {
305     case 2:
306       if (simplex) {
307         PetscInt    numPoints[2]        = {4, 2};
308         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
309         PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
310         PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
311         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
312 
313         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
314       } else {
315         PetscInt    numPoints[2]        = {6, 2};
316         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
317         PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
318         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
319         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};
320 
321         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
322       }
323       break;
324     case 3:
325       if (simplex) {
326         PetscInt    numPoints[2]        = {5, 2};
327         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
328         PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
329         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
330         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};
331 
332         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
333       } else {
334         PetscInt    numPoints[2]         = {12, 2};
335         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
336         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
337         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
338         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};
339 
340         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
341       }
342       break;
343     default:
344       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
345     }
346   }
347   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
348   *newdm = dm;
349   if (refinementLimit > 0.0) {
350     DM          rdm;
351     const char *name;
352 
353     PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE));
354     PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit));
355     PetscCall(DMRefine(*newdm, comm, &rdm));
356     PetscCall(PetscObjectGetName((PetscObject)*newdm, &name));
357     PetscCall(PetscObjectSetName((PetscObject)rdm, name));
358     PetscCall(DMDestroy(newdm));
359     *newdm = rdm;
360   }
361   if (interpolate) {
362     DM idm;
363 
364     PetscCall(DMPlexInterpolate(*newdm, &idm));
365     PetscCall(DMDestroy(newdm));
366     *newdm = idm;
367   }
368   PetscFunctionReturn(PETSC_SUCCESS);
369 }
370 
371 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
372 {
373   const PetscInt numVertices    = 2;
374   PetscInt       markerRight    = 1;
375   PetscInt       markerLeft     = 1;
376   PetscBool      markerSeparate = PETSC_FALSE;
377   Vec            coordinates;
378   PetscSection   coordSection;
379   PetscScalar   *coords;
380   PetscInt       coordSize;
381   PetscMPIInt    rank;
382   PetscInt       cdim = 1, v;
383 
384   PetscFunctionBegin;
385   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
386   if (markerSeparate) {
387     markerRight = 2;
388     markerLeft  = 1;
389   }
390   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
391   if (rank == 0) {
392     PetscCall(DMPlexSetChart(dm, 0, numVertices));
393     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
394     PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft));
395     PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight));
396   }
397   PetscCall(DMPlexSymmetrize(dm));
398   PetscCall(DMPlexStratify(dm));
399   /* Build coordinates */
400   PetscCall(DMSetCoordinateDim(dm, cdim));
401   PetscCall(DMGetCoordinateSection(dm, &coordSection));
402   PetscCall(PetscSectionSetNumFields(coordSection, 1));
403   PetscCall(PetscSectionSetChart(coordSection, 0, numVertices));
404   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
405   for (v = 0; v < numVertices; ++v) {
406     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
407     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
408   }
409   PetscCall(PetscSectionSetUp(coordSection));
410   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
411   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
412   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
413   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
414   PetscCall(VecSetBlockSize(coordinates, cdim));
415   PetscCall(VecSetType(coordinates, VECSTANDARD));
416   PetscCall(VecGetArray(coordinates, &coords));
417   coords[0] = lower[0];
418   coords[1] = upper[0];
419   PetscCall(VecRestoreArray(coordinates, &coords));
420   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
421   PetscCall(VecDestroy(&coordinates));
422   PetscFunctionReturn(PETSC_SUCCESS);
423 }
424 
425 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
426 {
427   const PetscInt numVertices    = (edges[0] + 1) * (edges[1] + 1);
428   const PetscInt numEdges       = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1];
429   PetscInt       markerTop      = 1;
430   PetscInt       markerBottom   = 1;
431   PetscInt       markerRight    = 1;
432   PetscInt       markerLeft     = 1;
433   PetscBool      markerSeparate = PETSC_FALSE;
434   Vec            coordinates;
435   PetscSection   coordSection;
436   PetscScalar   *coords;
437   PetscInt       coordSize;
438   PetscMPIInt    rank;
439   PetscInt       v, vx, vy;
440 
441   PetscFunctionBegin;
442   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
443   if (markerSeparate) {
444     markerTop    = 3;
445     markerBottom = 1;
446     markerRight  = 2;
447     markerLeft   = 4;
448   }
449   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
450   if (rank == 0) {
451     PetscInt e, ex, ey;
452 
453     PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices));
454     for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
455     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
456     for (vx = 0; vx <= edges[0]; vx++) {
457       for (ey = 0; ey < edges[1]; ey++) {
458         PetscInt edge   = vx * edges[1] + ey + edges[0] * (edges[1] + 1);
459         PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges;
460         PetscInt cone[2];
461 
462         cone[0] = vertex;
463         cone[1] = vertex + edges[0] + 1;
464         PetscCall(DMPlexSetCone(dm, edge, cone));
465         if (vx == edges[0]) {
466           PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
467           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
468           if (ey == edges[1] - 1) {
469             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
470             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight));
471           }
472         } else if (vx == 0) {
473           PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
474           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
475           if (ey == edges[1] - 1) {
476             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
477             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft));
478           }
479         }
480       }
481     }
482     for (vy = 0; vy <= edges[1]; vy++) {
483       for (ex = 0; ex < edges[0]; ex++) {
484         PetscInt edge   = vy * edges[0] + ex;
485         PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges;
486         PetscInt cone[2];
487 
488         cone[0] = vertex;
489         cone[1] = vertex + 1;
490         PetscCall(DMPlexSetCone(dm, edge, cone));
491         if (vy == edges[1]) {
492           PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
493           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
494           if (ex == edges[0] - 1) {
495             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
496             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop));
497           }
498         } else if (vy == 0) {
499           PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
500           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
501           if (ex == edges[0] - 1) {
502             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
503             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom));
504           }
505         }
506       }
507     }
508   }
509   PetscCall(DMPlexSymmetrize(dm));
510   PetscCall(DMPlexStratify(dm));
511   /* Build coordinates */
512   PetscCall(DMSetCoordinateDim(dm, 2));
513   PetscCall(DMGetCoordinateSection(dm, &coordSection));
514   PetscCall(PetscSectionSetNumFields(coordSection, 1));
515   PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices));
516   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
517   for (v = numEdges; v < numEdges + numVertices; ++v) {
518     PetscCall(PetscSectionSetDof(coordSection, v, 2));
519     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
520   }
521   PetscCall(PetscSectionSetUp(coordSection));
522   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
523   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
524   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
525   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
526   PetscCall(VecSetBlockSize(coordinates, 2));
527   PetscCall(VecSetType(coordinates, VECSTANDARD));
528   PetscCall(VecGetArray(coordinates, &coords));
529   for (vy = 0; vy <= edges[1]; ++vy) {
530     for (vx = 0; vx <= edges[0]; ++vx) {
531       coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx;
532       coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy;
533     }
534   }
535   PetscCall(VecRestoreArray(coordinates, &coords));
536   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
537   PetscCall(VecDestroy(&coordinates));
538   PetscFunctionReturn(PETSC_SUCCESS);
539 }
540 
541 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
542 {
543   PetscInt     vertices[3], numVertices;
544   PetscInt     numFaces       = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2];
545   PetscInt     markerTop      = 1;
546   PetscInt     markerBottom   = 1;
547   PetscInt     markerFront    = 1;
548   PetscInt     markerBack     = 1;
549   PetscInt     markerRight    = 1;
550   PetscInt     markerLeft     = 1;
551   PetscBool    markerSeparate = PETSC_FALSE;
552   Vec          coordinates;
553   PetscSection coordSection;
554   PetscScalar *coords;
555   PetscInt     coordSize;
556   PetscMPIInt  rank;
557   PetscInt     v, vx, vy, vz;
558   PetscInt     voffset, iface = 0, cone[4];
559 
560   PetscFunctionBegin;
561   PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
562   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
563   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
564   if (markerSeparate) {
565     markerBottom = 1;
566     markerTop    = 2;
567     markerFront  = 3;
568     markerBack   = 4;
569     markerRight  = 5;
570     markerLeft   = 6;
571   }
572   vertices[0] = faces[0] + 1;
573   vertices[1] = faces[1] + 1;
574   vertices[2] = faces[2] + 1;
575   numVertices = vertices[0] * vertices[1] * vertices[2];
576   if (rank == 0) {
577     PetscInt f;
578 
579     PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices));
580     for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
581     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
582 
583     /* Side 0 (Top) */
584     for (vy = 0; vy < faces[1]; vy++) {
585       for (vx = 0; vx < faces[0]; vx++) {
586         voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx;
587         cone[0] = voffset;
588         cone[1] = voffset + 1;
589         cone[2] = voffset + vertices[0] + 1;
590         cone[3] = voffset + vertices[0];
591         PetscCall(DMPlexSetCone(dm, iface, cone));
592         PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop));
593         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop));
594         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop));
595         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop));
596         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop));
597         iface++;
598       }
599     }
600 
601     /* Side 1 (Bottom) */
602     for (vy = 0; vy < faces[1]; vy++) {
603       for (vx = 0; vx < faces[0]; vx++) {
604         voffset = numFaces + vy * (faces[0] + 1) + vx;
605         cone[0] = voffset + 1;
606         cone[1] = voffset;
607         cone[2] = voffset + vertices[0];
608         cone[3] = voffset + vertices[0] + 1;
609         PetscCall(DMPlexSetCone(dm, iface, cone));
610         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom));
611         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom));
612         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom));
613         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom));
614         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom));
615         iface++;
616       }
617     }
618 
619     /* Side 2 (Front) */
620     for (vz = 0; vz < faces[2]; vz++) {
621       for (vx = 0; vx < faces[0]; vx++) {
622         voffset = numFaces + vz * vertices[0] * vertices[1] + vx;
623         cone[0] = voffset;
624         cone[1] = voffset + 1;
625         cone[2] = voffset + vertices[0] * vertices[1] + 1;
626         cone[3] = voffset + vertices[0] * vertices[1];
627         PetscCall(DMPlexSetCone(dm, iface, cone));
628         PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront));
629         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront));
630         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront));
631         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront));
632         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront));
633         iface++;
634       }
635     }
636 
637     /* Side 3 (Back) */
638     for (vz = 0; vz < faces[2]; vz++) {
639       for (vx = 0; vx < faces[0]; vx++) {
640         voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx;
641         cone[0] = voffset + vertices[0] * vertices[1];
642         cone[1] = voffset + vertices[0] * vertices[1] + 1;
643         cone[2] = voffset + 1;
644         cone[3] = voffset;
645         PetscCall(DMPlexSetCone(dm, iface, cone));
646         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack));
647         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack));
648         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack));
649         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack));
650         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack));
651         iface++;
652       }
653     }
654 
655     /* Side 4 (Left) */
656     for (vz = 0; vz < faces[2]; vz++) {
657       for (vy = 0; vy < faces[1]; vy++) {
658         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0];
659         cone[0] = voffset;
660         cone[1] = voffset + vertices[0] * vertices[1];
661         cone[2] = voffset + vertices[0] * vertices[1] + vertices[0];
662         cone[3] = voffset + vertices[0];
663         PetscCall(DMPlexSetCone(dm, iface, cone));
664         PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft));
665         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft));
666         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft));
667         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft));
668         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft));
669         iface++;
670       }
671     }
672 
673     /* Side 5 (Right) */
674     for (vz = 0; vz < faces[2]; vz++) {
675       for (vy = 0; vy < faces[1]; vy++) {
676         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0];
677         cone[0] = voffset + vertices[0] * vertices[1];
678         cone[1] = voffset;
679         cone[2] = voffset + vertices[0];
680         cone[3] = voffset + vertices[0] * vertices[1] + vertices[0];
681         PetscCall(DMPlexSetCone(dm, iface, cone));
682         PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight));
683         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight));
684         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight));
685         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight));
686         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight));
687         iface++;
688       }
689     }
690   }
691   PetscCall(DMPlexSymmetrize(dm));
692   PetscCall(DMPlexStratify(dm));
693   /* Build coordinates */
694   PetscCall(DMSetCoordinateDim(dm, 3));
695   PetscCall(DMGetCoordinateSection(dm, &coordSection));
696   PetscCall(PetscSectionSetNumFields(coordSection, 1));
697   PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices));
698   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
699   for (v = numFaces; v < numFaces + numVertices; ++v) {
700     PetscCall(PetscSectionSetDof(coordSection, v, 3));
701     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
702   }
703   PetscCall(PetscSectionSetUp(coordSection));
704   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
705   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
706   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
707   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
708   PetscCall(VecSetBlockSize(coordinates, 3));
709   PetscCall(VecSetType(coordinates, VECSTANDARD));
710   PetscCall(VecGetArray(coordinates, &coords));
711   for (vz = 0; vz <= faces[2]; ++vz) {
712     for (vy = 0; vy <= faces[1]; ++vy) {
713       for (vx = 0; vx <= faces[0]; ++vx) {
714         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx;
715         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy;
716         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz;
717       }
718     }
719   }
720   PetscCall(VecRestoreArray(coordinates, &coords));
721   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
722   PetscCall(VecDestroy(&coordinates));
723   PetscFunctionReturn(PETSC_SUCCESS);
724 }
725 
726 static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate)
727 {
728   PetscFunctionBegin;
729   PetscValidLogicalCollectiveInt(dm, dim, 2);
730   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
731   PetscCall(DMSetDimension(dm, dim - 1));
732   PetscCall(DMSetCoordinateDim(dm, dim));
733   switch (dim) {
734   case 1:
735     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces));
736     break;
737   case 2:
738     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces));
739     break;
740   case 3:
741     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces));
742     break;
743   default:
744     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim);
745   }
746   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
747   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
748   PetscFunctionReturn(PETSC_SUCCESS);
749 }
750 
751 /*@C
752   DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra).
753 
754   Collective
755 
756   Input Parameters:
757 + comm        - The communicator for the `DM` object
758 . dim         - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1
759 . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
760 . lower       - The lower left corner, or `NULL` for (0, 0, 0)
761 . upper       - The upper right corner, or `NULL` for (1, 1, 1)
762 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
763 
764   Output Parameter:
765 . dm - The `DM` object
766 
767   Level: beginner
768 
769 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()`
770 @*/
771 PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
772 {
773   PetscInt  fac[3] = {1, 1, 1};
774   PetscReal low[3] = {0, 0, 0};
775   PetscReal upp[3] = {1, 1, 1};
776 
777   PetscFunctionBegin;
778   PetscCall(DMCreate(comm, dm));
779   PetscCall(DMSetType(*dm, DMPLEX));
780   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate));
781   PetscFunctionReturn(PETSC_SUCCESS);
782 }
783 
784 static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd)
785 {
786   PetscInt     i, fStart, fEnd, numCells = 0, numVerts = 0;
787   PetscInt     numPoints[2], *coneSize, *cones, *coneOrientations;
788   PetscScalar *vertexCoords;
789   PetscReal    L, maxCell;
790   PetscBool    markerSeparate = PETSC_FALSE;
791   PetscInt     markerLeft = 1, faceMarkerLeft = 1;
792   PetscInt     markerRight = 1, faceMarkerRight = 2;
793   PetscBool    wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
794   PetscMPIInt  rank;
795 
796   PetscFunctionBegin;
797   PetscAssertPointer(dm, 1);
798 
799   PetscCall(DMSetDimension(dm, 1));
800   PetscCall(DMCreateLabel(dm, "marker"));
801   PetscCall(DMCreateLabel(dm, "Face Sets"));
802 
803   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
804   if (rank == 0) numCells = segments;
805   if (rank == 0) numVerts = segments + (wrap ? 0 : 1);
806 
807   numPoints[0] = numVerts;
808   numPoints[1] = numCells;
809   PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords));
810   PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts));
811   for (i = 0; i < numCells; ++i) coneSize[i] = 2;
812   for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0;
813   for (i = 0; i < numCells; ++i) {
814     cones[2 * i]     = numCells + i % numVerts;
815     cones[2 * i + 1] = numCells + (i + 1) % numVerts;
816   }
817   for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells);
818   PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
819   PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords));
820 
821   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
822   if (markerSeparate) {
823     markerLeft  = faceMarkerLeft;
824     markerRight = faceMarkerRight;
825   }
826   if (!wrap && rank == 0) {
827     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
828     PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft));
829     PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight));
830     PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft));
831     PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight));
832   }
833   if (wrap) {
834     L       = upper - lower;
835     maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments));
836     PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L));
837   }
838   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
839   PetscFunctionReturn(PETSC_SUCCESS);
840 }
841 
842 static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
843 {
844   DM      boundary, vol;
845   DMLabel bdlabel;
846 
847   PetscFunctionBegin;
848   PetscAssertPointer(dm, 1);
849   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");
850   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary));
851   PetscCall(DMSetType(boundary, DMPLEX));
852   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE));
853   PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol));
854   PetscCall(DMGetLabel(vol, "marker", &bdlabel));
855   if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel));
856   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol));
857   PetscCall(DMPlexReplace_Internal(dm, &vol));
858   PetscCall(DMDestroy(&boundary));
859   PetscFunctionReturn(PETSC_SUCCESS);
860 }
861 
862 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
863 {
864   DMLabel     cutLabel  = NULL;
865   PetscInt    markerTop = 1, faceMarkerTop = 1;
866   PetscInt    markerBottom = 1, faceMarkerBottom = 1;
867   PetscInt    markerFront = 1, faceMarkerFront = 1;
868   PetscInt    markerBack = 1, faceMarkerBack = 1;
869   PetscInt    markerRight = 1, faceMarkerRight = 1;
870   PetscInt    markerLeft = 1, faceMarkerLeft = 1;
871   PetscInt    dim;
872   PetscBool   markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
873   PetscMPIInt rank;
874 
875   PetscFunctionBegin;
876   PetscCall(DMGetDimension(dm, &dim));
877   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
878   PetscCall(DMCreateLabel(dm, "marker"));
879   PetscCall(DMCreateLabel(dm, "Face Sets"));
880   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
881   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) {
882     if (cutMarker) {
883       PetscCall(DMCreateLabel(dm, "periodic_cut"));
884       PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
885     }
886   }
887   switch (dim) {
888   case 2:
889     faceMarkerTop    = 3;
890     faceMarkerBottom = 1;
891     faceMarkerRight  = 2;
892     faceMarkerLeft   = 4;
893     break;
894   case 3:
895     faceMarkerBottom = 1;
896     faceMarkerTop    = 2;
897     faceMarkerFront  = 3;
898     faceMarkerBack   = 4;
899     faceMarkerRight  = 5;
900     faceMarkerLeft   = 6;
901     break;
902   default:
903     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
904   }
905   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
906   if (markerSeparate) {
907     markerBottom = faceMarkerBottom;
908     markerTop    = faceMarkerTop;
909     markerFront  = faceMarkerFront;
910     markerBack   = faceMarkerBack;
911     markerRight  = faceMarkerRight;
912     markerLeft   = faceMarkerLeft;
913   }
914   {
915     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
916     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
917     const PetscInt numZEdges    = rank == 0 ? edges[2] : 0;
918     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0;
919     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0;
920     const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0;
921     const PetscInt numCells     = numXEdges * numYEdges * numZEdges;
922     const PetscInt numXFaces    = numYEdges * numZEdges;
923     const PetscInt numYFaces    = numXEdges * numZEdges;
924     const PetscInt numZFaces    = numXEdges * numYEdges;
925     const PetscInt numTotXFaces = numXVertices * numXFaces;
926     const PetscInt numTotYFaces = numYVertices * numYFaces;
927     const PetscInt numTotZFaces = numZVertices * numZFaces;
928     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
929     const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices;
930     const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices;
931     const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices;
932     const PetscInt numVertices  = numXVertices * numYVertices * numZVertices;
933     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
934     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
935     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
936     const PetscInt firstYFace   = firstXFace + numTotXFaces;
937     const PetscInt firstZFace   = firstYFace + numTotYFaces;
938     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
939     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
940     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
941     Vec            coordinates;
942     PetscSection   coordSection;
943     PetscScalar   *coords;
944     PetscInt       coordSize;
945     PetscInt       v, vx, vy, vz;
946     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;
947 
948     PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices));
949     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
950     for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
951     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
952     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
953     /* Build cells */
954     for (fz = 0; fz < numZEdges; ++fz) {
955       for (fy = 0; fy < numYEdges; ++fy) {
956         for (fx = 0; fx < numXEdges; ++fx) {
957           PetscInt cell  = (fz * numYEdges + fy) * numXEdges + fx;
958           PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
959           PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices);
960           PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
961           PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices);
962           PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
963           PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices);
964           /* B,  T,  F,  K,  R,  L */
965           PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */
966           PetscInt cone[6];
967 
968           /* no boundary twisting in 3D */
969           cone[0] = faceB;
970           cone[1] = faceT;
971           cone[2] = faceF;
972           cone[3] = faceK;
973           cone[4] = faceR;
974           cone[5] = faceL;
975           PetscCall(DMPlexSetCone(dm, cell, cone));
976           PetscCall(DMPlexSetConeOrientation(dm, cell, ornt));
977           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
978           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
979           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
980         }
981       }
982     }
983     /* Build x faces */
984     for (fz = 0; fz < numZEdges; ++fz) {
985       for (fy = 0; fy < numYEdges; ++fy) {
986         for (fx = 0; fx < numXVertices; ++fx) {
987           PetscInt face    = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
988           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
989           PetscInt edgeR   = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz;
990           PetscInt edgeB   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
991           PetscInt edgeT   = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy;
992           PetscInt ornt[4] = {0, 0, -1, -1};
993           PetscInt cone[4];
994 
995           if (dim == 3) {
996             /* markers */
997             if (bdX != DM_BOUNDARY_PERIODIC) {
998               if (fx == numXVertices - 1) {
999                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight));
1000                 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight));
1001               } else if (fx == 0) {
1002                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft));
1003                 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft));
1004               }
1005             }
1006           }
1007           cone[0] = edgeB;
1008           cone[1] = edgeR;
1009           cone[2] = edgeT;
1010           cone[3] = edgeL;
1011           PetscCall(DMPlexSetCone(dm, face, cone));
1012           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1013         }
1014       }
1015     }
1016     /* Build y faces */
1017     for (fz = 0; fz < numZEdges; ++fz) {
1018       for (fx = 0; fx < numXEdges; ++fx) {
1019         for (fy = 0; fy < numYVertices; ++fy) {
1020           PetscInt face    = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
1021           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
1022           PetscInt edgeR   = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz;
1023           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1024           PetscInt edgeT   = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx;
1025           PetscInt ornt[4] = {0, 0, -1, -1};
1026           PetscInt cone[4];
1027 
1028           if (dim == 3) {
1029             /* markers */
1030             if (bdY != DM_BOUNDARY_PERIODIC) {
1031               if (fy == numYVertices - 1) {
1032                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack));
1033                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack));
1034               } else if (fy == 0) {
1035                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront));
1036                 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront));
1037               }
1038             }
1039           }
1040           cone[0] = edgeB;
1041           cone[1] = edgeR;
1042           cone[2] = edgeT;
1043           cone[3] = edgeL;
1044           PetscCall(DMPlexSetCone(dm, face, cone));
1045           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1046         }
1047       }
1048     }
1049     /* Build z faces */
1050     for (fy = 0; fy < numYEdges; ++fy) {
1051       for (fx = 0; fx < numXEdges; ++fx) {
1052         for (fz = 0; fz < numZVertices; fz++) {
1053           PetscInt face    = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
1054           PetscInt edgeL   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
1055           PetscInt edgeR   = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy;
1056           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
1057           PetscInt edgeT   = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx;
1058           PetscInt ornt[4] = {0, 0, -1, -1};
1059           PetscInt cone[4];
1060 
1061           if (dim == 2) {
1062             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) {
1063               edgeR += numYEdges - 1 - 2 * fy;
1064               ornt[1] = -1;
1065             }
1066             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) {
1067               edgeT += numXEdges - 1 - 2 * fx;
1068               ornt[2] = 0;
1069             }
1070             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1071             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1072           } else {
1073             /* markers */
1074             if (bdZ != DM_BOUNDARY_PERIODIC) {
1075               if (fz == numZVertices - 1) {
1076                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop));
1077                 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop));
1078               } else if (fz == 0) {
1079                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom));
1080                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom));
1081               }
1082             }
1083           }
1084           cone[0] = edgeB;
1085           cone[1] = edgeR;
1086           cone[2] = edgeT;
1087           cone[3] = edgeL;
1088           PetscCall(DMPlexSetCone(dm, face, cone));
1089           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
1090         }
1091       }
1092     }
1093     /* Build Z edges*/
1094     for (vy = 0; vy < numYVertices; vy++) {
1095       for (vx = 0; vx < numXVertices; vx++) {
1096         for (ez = 0; ez < numZEdges; ez++) {
1097           const PetscInt edge    = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez;
1098           const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx;
1099           const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx;
1100           PetscInt       cone[2];
1101 
1102           cone[0] = vertexB;
1103           cone[1] = vertexT;
1104           PetscCall(DMPlexSetCone(dm, edge, cone));
1105           if (dim == 3) {
1106             if (bdX != DM_BOUNDARY_PERIODIC) {
1107               if (vx == numXVertices - 1) {
1108                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1109                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1110                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1111               } else if (vx == 0) {
1112                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1113                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1114                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1115               }
1116             }
1117             if (bdY != DM_BOUNDARY_PERIODIC) {
1118               if (vy == numYVertices - 1) {
1119                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1120                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1121                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1122               } else if (vy == 0) {
1123                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1124                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1125                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1126               }
1127             }
1128           }
1129         }
1130       }
1131     }
1132     /* Build Y edges*/
1133     for (vz = 0; vz < numZVertices; vz++) {
1134       for (vx = 0; vx < numXVertices; vx++) {
1135         for (ey = 0; ey < numYEdges; ey++) {
1136           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx;
1137           const PetscInt edge    = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey;
1138           const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx;
1139           const PetscInt vertexK = firstVertex + nextv;
1140           PetscInt       cone[2];
1141 
1142           cone[0] = vertexF;
1143           cone[1] = vertexK;
1144           PetscCall(DMPlexSetCone(dm, edge, cone));
1145           if (dim == 2) {
1146             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1147               if (vx == numXVertices - 1) {
1148                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1149                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1150                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1151                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1152               } else if (vx == 0) {
1153                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1154                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1155                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1156                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1157               }
1158             } else {
1159               if (vx == 0 && cutLabel) {
1160                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1161                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1162                 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1163               }
1164             }
1165           } else {
1166             if (bdX != DM_BOUNDARY_PERIODIC) {
1167               if (vx == numXVertices - 1) {
1168                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1169                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1170                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1171               } else if (vx == 0) {
1172                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1173                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1174                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1175               }
1176             }
1177             if (bdZ != DM_BOUNDARY_PERIODIC) {
1178               if (vz == numZVertices - 1) {
1179                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1180                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1181                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1182               } else if (vz == 0) {
1183                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1184                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1185                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1186               }
1187             }
1188           }
1189         }
1190       }
1191     }
1192     /* Build X edges*/
1193     for (vz = 0; vz < numZVertices; vz++) {
1194       for (vy = 0; vy < numYVertices; vy++) {
1195         for (ex = 0; ex < numXEdges; ex++) {
1196           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices;
1197           const PetscInt edge    = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex;
1198           const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex;
1199           const PetscInt vertexR = firstVertex + nextv;
1200           PetscInt       cone[2];
1201 
1202           cone[0] = vertexL;
1203           cone[1] = vertexR;
1204           PetscCall(DMPlexSetCone(dm, edge, cone));
1205           if (dim == 2) {
1206             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1207               if (vy == numYVertices - 1) {
1208                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1209                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1210                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1211                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1212               } else if (vy == 0) {
1213                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1214                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1215                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1216                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1217               }
1218             } else {
1219               if (vy == 0 && cutLabel) {
1220                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
1221                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1222                 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
1223               }
1224             }
1225           } else {
1226             if (bdY != DM_BOUNDARY_PERIODIC) {
1227               if (vy == numYVertices - 1) {
1228                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1229                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1230                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1231               } else if (vy == 0) {
1232                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1233                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1234                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
1235               }
1236             }
1237             if (bdZ != DM_BOUNDARY_PERIODIC) {
1238               if (vz == numZVertices - 1) {
1239                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1240                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1241                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1242               } else if (vz == 0) {
1243                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1244                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1245                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1246               }
1247             }
1248           }
1249         }
1250       }
1251     }
1252     PetscCall(DMPlexSymmetrize(dm));
1253     PetscCall(DMPlexStratify(dm));
1254     /* Build coordinates */
1255     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1256     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1257     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1258     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1259     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1260       PetscCall(PetscSectionSetDof(coordSection, v, dim));
1261       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1262     }
1263     PetscCall(PetscSectionSetUp(coordSection));
1264     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1265     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1266     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1267     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1268     PetscCall(VecSetBlockSize(coordinates, dim));
1269     PetscCall(VecSetType(coordinates, VECSTANDARD));
1270     PetscCall(VecGetArray(coordinates, &coords));
1271     for (vz = 0; vz < numZVertices; ++vz) {
1272       for (vy = 0; vy < numYVertices; ++vy) {
1273         for (vx = 0; vx < numXVertices; ++vx) {
1274           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1275           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1276           if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz;
1277         }
1278       }
1279     }
1280     PetscCall(VecRestoreArray(coordinates, &coords));
1281     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1282     PetscCall(VecDestroy(&coordinates));
1283   }
1284   PetscFunctionReturn(PETSC_SUCCESS);
1285 }
1286 
1287 static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1288 {
1289   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1290   PetscInt       fac[3] = {0, 0, 0}, d;
1291 
1292   PetscFunctionBegin;
1293   PetscAssertPointer(dm, 1);
1294   PetscValidLogicalCollectiveInt(dm, dim, 2);
1295   PetscCall(DMSetDimension(dm, dim));
1296   for (d = 0; d < dim; ++d) {
1297     fac[d] = faces[d];
1298     bdt[d] = periodicity[d];
1299   }
1300   PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2]));
1301   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))) {
1302     PetscReal L[3]       = {-1., -1., 0.};
1303     PetscReal maxCell[3] = {-1., -1., 0.};
1304 
1305     for (d = 0; d < dim; ++d) {
1306       if (periodicity[d] != DM_BOUNDARY_NONE) {
1307         L[d]       = upper[d] - lower[d];
1308         maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d]));
1309       }
1310     }
1311     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1312   }
1313   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1314   PetscFunctionReturn(PETSC_SUCCESS);
1315 }
1316 
1317 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)
1318 {
1319   PetscFunctionBegin;
1320   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1321   if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1322   else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0]));
1323   else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
1324   else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity));
1325   if (!interpolate && dim > 1 && !simplex) {
1326     DM udm;
1327 
1328     PetscCall(DMPlexUninterpolate(dm, &udm));
1329     PetscCall(DMPlexCopyCoordinates(dm, udm));
1330     PetscCall(DMPlexReplace_Internal(dm, &udm));
1331   }
1332   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
1333   PetscFunctionReturn(PETSC_SUCCESS);
1334 }
1335 
1336 /*@C
1337   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).
1338 
1339   Collective
1340 
1341   Input Parameters:
1342 + comm        - The communicator for the `DM` object
1343 . dim         - The spatial dimension
1344 . simplex     - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells
1345 . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1346 . lower       - The lower left corner, or `NULL` for (0, 0, 0)
1347 . upper       - The upper right corner, or `NULL` for (1, 1, 1)
1348 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
1349 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1350 
1351   Output Parameter:
1352 . dm - The `DM` object
1353 
1354   Level: beginner
1355 
1356   Note:
1357   To customize this mesh using options, use
1358 .vb
1359   DMCreate(comm, &dm);
1360   DMSetType(dm, DMPLEX);
1361   DMSetFromOptions(dm);
1362 .ve
1363   and use the options in `DMSetFromOptions()`.
1364 
1365   Here is the numbering returned for 2 faces in each direction for tensor cells\:
1366 .vb
1367  10---17---11---18----12
1368   |         |         |
1369   |         |         |
1370  20    2   22    3    24
1371   |         |         |
1372   |         |         |
1373   7---15----8---16----9
1374   |         |         |
1375   |         |         |
1376  19    0   21    1   23
1377   |         |         |
1378   |         |         |
1379   4---13----5---14----6
1380 .ve
1381   and for simplicial cells
1382 .vb
1383  14----8---15----9----16
1384   |\     5  |\      7 |
1385   | \       | \       |
1386  13   2    14    3    15
1387   | 4   \   | 6   \   |
1388   |       \ |       \ |
1389  11----6---12----7----13
1390   |\        |\        |
1391   | \    1  | \     3 |
1392  10   0    11    1    12
1393   | 0   \   | 2   \   |
1394   |       \ |       \ |
1395   8----4----9----5----10
1396 .ve
1397 
1398 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
1399 @*/
1400 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)
1401 {
1402   PetscInt       fac[3] = {1, 1, 1};
1403   PetscReal      low[3] = {0, 0, 0};
1404   PetscReal      upp[3] = {1, 1, 1};
1405   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1406 
1407   PetscFunctionBegin;
1408   PetscCall(DMCreate(comm, dm));
1409   PetscCall(DMSetType(*dm, DMPLEX));
1410   PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate));
1411   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1412   PetscFunctionReturn(PETSC_SUCCESS);
1413 }
1414 
1415 static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1416 {
1417   DM       bdm, vol;
1418   PetscInt i;
1419 
1420   PetscFunctionBegin;
1421   // TODO Now we can support periodicity
1422   for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported");
1423   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm));
1424   PetscCall(DMSetType(bdm, DMPLEX));
1425   PetscCall(DMSetDimension(bdm, 2));
1426   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
1427   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
1428   PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, &vol));
1429   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
1430   PetscCall(DMDestroy(&bdm));
1431   PetscCall(DMPlexReplace_Internal(dm, &vol));
1432   if (lower[2] != 0.0) {
1433     Vec          v;
1434     PetscScalar *x;
1435     PetscInt     cDim, n;
1436 
1437     PetscCall(DMGetCoordinatesLocal(dm, &v));
1438     PetscCall(VecGetBlockSize(v, &cDim));
1439     PetscCall(VecGetLocalSize(v, &n));
1440     PetscCall(VecGetArray(v, &x));
1441     x += cDim;
1442     for (i = 0; i < n; i += cDim) x[i] += lower[2];
1443     PetscCall(VecRestoreArray(v, &x));
1444     PetscCall(DMSetCoordinatesLocal(dm, v));
1445   }
1446   PetscFunctionReturn(PETSC_SUCCESS);
1447 }
1448 
1449 /*@
1450   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tessellating the (x,y) plane and extruding in the third direction using wedge cells.
1451 
1452   Collective
1453 
1454   Input Parameters:
1455 + comm        - The communicator for the `DM` object
1456 . faces       - Number of faces per dimension, or `NULL` for (1, 1, 1)
1457 . lower       - The lower left corner, or `NULL` for (0, 0, 0)
1458 . upper       - The upper right corner, or `NULL` for (1, 1, 1)
1459 . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
1460 . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1461 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1462 
1463   Output Parameter:
1464 . dm - The `DM` object
1465 
1466   Level: beginner
1467 
1468 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
1469 @*/
1470 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
1471 {
1472   PetscInt       fac[3] = {1, 1, 1};
1473   PetscReal      low[3] = {0, 0, 0};
1474   PetscReal      upp[3] = {1, 1, 1};
1475   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1476 
1477   PetscFunctionBegin;
1478   PetscCall(DMCreate(comm, dm));
1479   PetscCall(DMSetType(*dm, DMPLEX));
1480   PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt));
1481   if (!interpolate) {
1482     DM udm;
1483 
1484     PetscCall(DMPlexUninterpolate(*dm, &udm));
1485     PetscCall(DMPlexReplace_Internal(*dm, &udm));
1486   }
1487   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
1488   PetscFunctionReturn(PETSC_SUCCESS);
1489 }
1490 
1491 /*
1492   DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension.
1493 
1494   Input Parameters:
1495 + len - The length of the tuple
1496 . max - The maximum for each dimension, so values are in [0, max)
1497 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
1498 
1499   Output Parameter:
1500 . tup - A tuple of `len` integers whose entries are at most `max`
1501 
1502   Level: developer
1503 
1504   Note:
1505   Ordering is lexicographic with lowest index as least significant in ordering.
1506   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}.
1507 
1508 .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal()
1509 */
1510 static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[])
1511 {
1512   PetscInt i;
1513 
1514   PetscFunctionBegin;
1515   for (i = 0; i < len; ++i) {
1516     if (tup[i] < max[i] - 1) {
1517       break;
1518     } else {
1519       tup[i] = 0;
1520     }
1521   }
1522   if (i == len) tup[i - 1] = max[i - 1];
1523   else ++tup[i];
1524   PetscFunctionReturn(PETSC_SUCCESS);
1525 }
1526 
1527 static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[])
1528 {
1529   PetscInt i, idx = tup[len - 1];
1530 
1531   for (i = len - 2; i >= 0; --i) {
1532     idx *= max[i];
1533     idx += tup[i];
1534   }
1535   return idx;
1536 }
1537 
1538 static PetscErrorCode DestroyExtent_Private(void *extent)
1539 {
1540   return PetscFree(extent);
1541 }
1542 
1543 static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], const DMBoundaryType bd[])
1544 {
1545   Vec          coordinates;
1546   PetscSection coordSection;
1547   DMLabel      cutLabel    = NULL;
1548   PetscBool    cutMarker   = PETSC_FALSE;
1549   PetscBool    periodic    = PETSC_FALSE;
1550   PetscInt     numCells    = 1, c;
1551   PetscInt     numVertices = 1, v;
1552   PetscScalar *coords;
1553   PetscInt    *vertices, *vert, *vtmp, *supp, cone[2];
1554   PetscInt     d, e, cell = 0, coordSize;
1555   PetscMPIInt  rank;
1556 
1557   PetscFunctionBegin;
1558   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1559   PetscCall(DMSetDimension(dm, dim));
1560   PetscCall(PetscCalloc4(dim, &vertices, dim, &vert, dim, &vtmp, 2 * dim, &supp));
1561   PetscCall(DMCreateLabel(dm, "marker"));
1562   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
1563   for (d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE;
1564   if (periodic && cutMarker) {
1565     PetscCall(DMCreateLabel(dm, "periodic_cut"));
1566     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
1567   }
1568   for (d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Hypercubic mesh must be periodic now");
1569   for (d = 0; d < dim; ++d) {
1570     vertices[d] = edges[d];
1571     numVertices *= vertices[d];
1572   }
1573   numCells = numVertices * dim;
1574   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1575   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2));
1576   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim));
1577   /* TODO Loop over boundary and reset support sizes */
1578   PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */
1579   /* Build cell cones and vertex supports */
1580   PetscCall(DMCreateLabel(dm, "celltype"));
1581   while (vert[dim - 1] < vertices[dim - 1]) {
1582     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells;
1583     PetscInt       s      = 0;
1584 
1585     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1586     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1587     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1588     PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT));
1589     for (d = 0; d < dim; ++d) {
1590       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1591       vtmp[d] = (vert[d] + 1) % vertices[d];
1592       cone[0] = vertex;
1593       cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells;
1594       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Vertex %" PetscInt_FMT ":", cone[1]));
1595       for (e = 0; e < dim; ++e) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vtmp[e]));
1596       PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1597       PetscCall(DMPlexSetCone(dm, cell, cone));
1598       PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT));
1599       PetscCall(PetscPrintf(PETSC_COMM_SELF, "  Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]));
1600       ++cell;
1601     }
1602     for (d = 0; d < dim; ++d) {
1603       for (e = 0; e < dim; ++e) vtmp[e] = vert[e];
1604       vtmp[d]   = (vert[d] + vertices[d] - 1) % vertices[d];
1605       supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d;
1606       supp[s++] = (vertex - numCells) * dim + d;
1607       PetscCall(DMPlexSetSupport(dm, vertex, supp));
1608     }
1609     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1610   }
1611   PetscCall(DMPlexStratify(dm));
1612   /* Build coordinates */
1613   PetscCall(DMGetCoordinateSection(dm, &coordSection));
1614   PetscCall(PetscSectionSetNumFields(coordSection, 1));
1615   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
1616   PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
1617   for (v = numCells; v < numCells + numVertices; ++v) {
1618     PetscCall(PetscSectionSetDof(coordSection, v, dim));
1619     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
1620   }
1621   PetscCall(PetscSectionSetUp(coordSection));
1622   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1623   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1624   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1625   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1626   PetscCall(VecSetBlockSize(coordinates, dim));
1627   PetscCall(VecSetType(coordinates, VECSTANDARD));
1628   PetscCall(VecGetArray(coordinates, &coords));
1629   for (d = 0; d < dim; ++d) vert[d] = 0;
1630   while (vert[dim - 1] < vertices[dim - 1]) {
1631     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert);
1632 
1633     for (d = 0; d < dim; ++d) coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / vertices[d]) * vert[d];
1634     PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT ":", vertex));
1635     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, vert[d]));
1636     for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(coords[vertex * dim + d])));
1637     PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1638     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
1639   }
1640   PetscCall(VecRestoreArray(coordinates, &coords));
1641   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1642   PetscCall(VecDestroy(&coordinates));
1643   PetscCall(PetscFree4(vertices, vert, vtmp, supp));
1644   //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper));
1645   // Attach the extent
1646   {
1647     PetscContainer c;
1648     PetscInt      *extent;
1649 
1650     PetscCall(PetscMalloc1(dim, &extent));
1651     for (PetscInt d = 0; d < dim; ++d) extent[d] = edges[d];
1652     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
1653     PetscCall(PetscContainerSetUserDestroy(c, DestroyExtent_Private));
1654     PetscCall(PetscContainerSetPointer(c, extent));
1655     PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c));
1656     PetscCall(PetscContainerDestroy(&c));
1657   }
1658   PetscFunctionReturn(PETSC_SUCCESS);
1659 }
1660 
1661 /*@C
1662   DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges.
1663 
1664   Collective
1665 
1666   Input Parameters:
1667 + comm  - The communicator for the DM object
1668 . dim   - The spatial dimension
1669 . edges - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
1670 . lower - The lower left corner, or `NULL` for (0, 0, 0)
1671 - upper - The upper right corner, or `NULL` for (1, 1, 1)
1672 
1673   Output Parameter:
1674 . dm - The DM object
1675 
1676   Level: beginner
1677 
1678   Note:
1679   If you want to customize this mesh using options, you just need to
1680 .vb
1681   DMCreate(comm, &dm);
1682   DMSetType(dm, DMPLEX);
1683   DMSetFromOptions(dm);
1684 .ve
1685   and use the options on the `DMSetFromOptions()` page.
1686 
1687   The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively,
1688 .vb
1689  18--0-19--2-20--4-18
1690   |     |     |     |
1691  13    15    17    13
1692   |     |     |     |
1693  24-12-25-14-26-16-24
1694   |     |     |     |
1695   7     9    11     7
1696   |     |     |     |
1697  21--6-22--8-23-10-21
1698   |     |     |     |
1699   1     3     5     1
1700   |     |     |     |
1701  18--0-19--2-20--4-18
1702 .ve
1703 
1704 .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
1705 @*/
1706 PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], DM *dm)
1707 {
1708   PetscInt       *edg;
1709   PetscReal      *low, *upp;
1710   DMBoundaryType *bdt;
1711   PetscInt        d;
1712 
1713   PetscFunctionBegin;
1714   PetscCall(DMCreate(comm, dm));
1715   PetscCall(DMSetType(*dm, DMPLEX));
1716   PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt));
1717   for (d = 0; d < dim; ++d) {
1718     edg[d] = edges ? edges[d] : 1;
1719     low[d] = lower ? lower[d] : 0.;
1720     upp[d] = upper ? upper[d] : 1.;
1721     bdt[d] = DM_BOUNDARY_PERIODIC;
1722   }
1723   PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, bdt));
1724   PetscCall(PetscFree4(edg, low, upp, bdt));
1725   PetscFunctionReturn(PETSC_SUCCESS);
1726 }
1727 
1728 /*@C
1729   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database.
1730 
1731   Logically Collective
1732 
1733   Input Parameters:
1734 + dm     - the `DM` context
1735 - prefix - the prefix to prepend to all option names
1736 
1737   Level: advanced
1738 
1739   Note:
1740   A hyphen (-) must NOT be given at the beginning of the prefix name.
1741   The first character of all runtime options is AUTOMATICALLY the hyphen.
1742 
1743 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()`
1744 @*/
1745 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1746 {
1747   DM_Plex *mesh = (DM_Plex *)dm->data;
1748 
1749   PetscFunctionBegin;
1750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1751   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
1752   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix));
1753   PetscFunctionReturn(PETSC_SUCCESS);
1754 }
1755 
1756 /* Remap geometry to cylinder
1757    TODO: This only works for a single refinement, then it is broken
1758 
1759      Interior square: Linear interpolation is correct
1760      The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1761      such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
1762 
1763        phi     = arctan(y/x)
1764        d_close = sqrt(1/8 + 1/4 sin^2(phi))
1765        d_far   = sqrt(1/2 + sin^2(phi))
1766 
1767      so we remap them using
1768 
1769        x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1770        y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
1771 
1772      If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1773 */
1774 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[])
1775 {
1776   const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
1777   const PetscReal ds2 = 0.5 * dis;
1778 
1779   if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) {
1780     f0[0] = u[0];
1781     f0[1] = u[1];
1782   } else {
1783     PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
1784 
1785     x    = PetscRealPart(u[0]);
1786     y    = PetscRealPart(u[1]);
1787     phi  = PetscAtan2Real(y, x);
1788     sinp = PetscSinReal(phi);
1789     cosp = PetscCosReal(phi);
1790     if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) {
1791       dc = PetscAbsReal(ds2 / sinp);
1792       df = PetscAbsReal(dis / sinp);
1793       xc = ds2 * x / PetscAbsReal(y);
1794       yc = ds2 * PetscSignReal(y);
1795     } else {
1796       dc = PetscAbsReal(ds2 / cosp);
1797       df = PetscAbsReal(dis / cosp);
1798       xc = ds2 * PetscSignReal(x);
1799       yc = ds2 * y / PetscAbsReal(x);
1800     }
1801     f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc);
1802     f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc);
1803   }
1804   f0[2] = u[2];
1805 }
1806 
1807 static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ)
1808 {
1809   const PetscInt dim = 3;
1810   PetscInt       numCells, numVertices;
1811   PetscMPIInt    rank;
1812 
1813   PetscFunctionBegin;
1814   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
1815   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1816   PetscCall(DMSetDimension(dm, dim));
1817   /* Create topology */
1818   {
1819     PetscInt cone[8], c;
1820 
1821     numCells    = rank == 0 ? 5 : 0;
1822     numVertices = rank == 0 ? 16 : 0;
1823     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1824       numCells *= 3;
1825       numVertices = rank == 0 ? 24 : 0;
1826     }
1827     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
1828     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8));
1829     PetscCall(DMSetUp(dm));
1830     if (rank == 0) {
1831       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1832         cone[0] = 15;
1833         cone[1] = 18;
1834         cone[2] = 17;
1835         cone[3] = 16;
1836         cone[4] = 31;
1837         cone[5] = 32;
1838         cone[6] = 33;
1839         cone[7] = 34;
1840         PetscCall(DMPlexSetCone(dm, 0, cone));
1841         cone[0] = 16;
1842         cone[1] = 17;
1843         cone[2] = 24;
1844         cone[3] = 23;
1845         cone[4] = 32;
1846         cone[5] = 36;
1847         cone[6] = 37;
1848         cone[7] = 33; /* 22 25 26 21 */
1849         PetscCall(DMPlexSetCone(dm, 1, cone));
1850         cone[0] = 18;
1851         cone[1] = 27;
1852         cone[2] = 24;
1853         cone[3] = 17;
1854         cone[4] = 34;
1855         cone[5] = 33;
1856         cone[6] = 37;
1857         cone[7] = 38;
1858         PetscCall(DMPlexSetCone(dm, 2, cone));
1859         cone[0] = 29;
1860         cone[1] = 27;
1861         cone[2] = 18;
1862         cone[3] = 15;
1863         cone[4] = 35;
1864         cone[5] = 31;
1865         cone[6] = 34;
1866         cone[7] = 38;
1867         PetscCall(DMPlexSetCone(dm, 3, cone));
1868         cone[0] = 29;
1869         cone[1] = 15;
1870         cone[2] = 16;
1871         cone[3] = 23;
1872         cone[4] = 35;
1873         cone[5] = 36;
1874         cone[6] = 32;
1875         cone[7] = 31;
1876         PetscCall(DMPlexSetCone(dm, 4, cone));
1877 
1878         cone[0] = 31;
1879         cone[1] = 34;
1880         cone[2] = 33;
1881         cone[3] = 32;
1882         cone[4] = 19;
1883         cone[5] = 22;
1884         cone[6] = 21;
1885         cone[7] = 20;
1886         PetscCall(DMPlexSetCone(dm, 5, cone));
1887         cone[0] = 32;
1888         cone[1] = 33;
1889         cone[2] = 37;
1890         cone[3] = 36;
1891         cone[4] = 22;
1892         cone[5] = 25;
1893         cone[6] = 26;
1894         cone[7] = 21;
1895         PetscCall(DMPlexSetCone(dm, 6, cone));
1896         cone[0] = 34;
1897         cone[1] = 38;
1898         cone[2] = 37;
1899         cone[3] = 33;
1900         cone[4] = 20;
1901         cone[5] = 21;
1902         cone[6] = 26;
1903         cone[7] = 28;
1904         PetscCall(DMPlexSetCone(dm, 7, cone));
1905         cone[0] = 35;
1906         cone[1] = 38;
1907         cone[2] = 34;
1908         cone[3] = 31;
1909         cone[4] = 30;
1910         cone[5] = 19;
1911         cone[6] = 20;
1912         cone[7] = 28;
1913         PetscCall(DMPlexSetCone(dm, 8, cone));
1914         cone[0] = 35;
1915         cone[1] = 31;
1916         cone[2] = 32;
1917         cone[3] = 36;
1918         cone[4] = 30;
1919         cone[5] = 25;
1920         cone[6] = 22;
1921         cone[7] = 19;
1922         PetscCall(DMPlexSetCone(dm, 9, cone));
1923 
1924         cone[0] = 19;
1925         cone[1] = 20;
1926         cone[2] = 21;
1927         cone[3] = 22;
1928         cone[4] = 15;
1929         cone[5] = 16;
1930         cone[6] = 17;
1931         cone[7] = 18;
1932         PetscCall(DMPlexSetCone(dm, 10, cone));
1933         cone[0] = 22;
1934         cone[1] = 21;
1935         cone[2] = 26;
1936         cone[3] = 25;
1937         cone[4] = 16;
1938         cone[5] = 23;
1939         cone[6] = 24;
1940         cone[7] = 17;
1941         PetscCall(DMPlexSetCone(dm, 11, cone));
1942         cone[0] = 20;
1943         cone[1] = 28;
1944         cone[2] = 26;
1945         cone[3] = 21;
1946         cone[4] = 18;
1947         cone[5] = 17;
1948         cone[6] = 24;
1949         cone[7] = 27;
1950         PetscCall(DMPlexSetCone(dm, 12, cone));
1951         cone[0] = 30;
1952         cone[1] = 28;
1953         cone[2] = 20;
1954         cone[3] = 19;
1955         cone[4] = 29;
1956         cone[5] = 15;
1957         cone[6] = 18;
1958         cone[7] = 27;
1959         PetscCall(DMPlexSetCone(dm, 13, cone));
1960         cone[0] = 30;
1961         cone[1] = 19;
1962         cone[2] = 22;
1963         cone[3] = 25;
1964         cone[4] = 29;
1965         cone[5] = 23;
1966         cone[6] = 16;
1967         cone[7] = 15;
1968         PetscCall(DMPlexSetCone(dm, 14, cone));
1969       } else {
1970         cone[0] = 5;
1971         cone[1] = 8;
1972         cone[2] = 7;
1973         cone[3] = 6;
1974         cone[4] = 9;
1975         cone[5] = 12;
1976         cone[6] = 11;
1977         cone[7] = 10;
1978         PetscCall(DMPlexSetCone(dm, 0, cone));
1979         cone[0] = 6;
1980         cone[1] = 7;
1981         cone[2] = 14;
1982         cone[3] = 13;
1983         cone[4] = 12;
1984         cone[5] = 15;
1985         cone[6] = 16;
1986         cone[7] = 11;
1987         PetscCall(DMPlexSetCone(dm, 1, cone));
1988         cone[0] = 8;
1989         cone[1] = 17;
1990         cone[2] = 14;
1991         cone[3] = 7;
1992         cone[4] = 10;
1993         cone[5] = 11;
1994         cone[6] = 16;
1995         cone[7] = 18;
1996         PetscCall(DMPlexSetCone(dm, 2, cone));
1997         cone[0] = 19;
1998         cone[1] = 17;
1999         cone[2] = 8;
2000         cone[3] = 5;
2001         cone[4] = 20;
2002         cone[5] = 9;
2003         cone[6] = 10;
2004         cone[7] = 18;
2005         PetscCall(DMPlexSetCone(dm, 3, cone));
2006         cone[0] = 19;
2007         cone[1] = 5;
2008         cone[2] = 6;
2009         cone[3] = 13;
2010         cone[4] = 20;
2011         cone[5] = 15;
2012         cone[6] = 12;
2013         cone[7] = 9;
2014         PetscCall(DMPlexSetCone(dm, 4, cone));
2015       }
2016     }
2017     PetscCall(DMPlexSymmetrize(dm));
2018     PetscCall(DMPlexStratify(dm));
2019   }
2020   /* Create cube geometry */
2021   {
2022     Vec             coordinates;
2023     PetscSection    coordSection;
2024     PetscScalar    *coords;
2025     PetscInt        coordSize, v;
2026     const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
2027     const PetscReal ds2 = dis / 2.0;
2028 
2029     /* Build coordinates */
2030     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2031     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2032     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2033     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2034     for (v = numCells; v < numCells + numVertices; ++v) {
2035       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2036       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2037     }
2038     PetscCall(PetscSectionSetUp(coordSection));
2039     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2040     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2041     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2042     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2043     PetscCall(VecSetBlockSize(coordinates, dim));
2044     PetscCall(VecSetType(coordinates, VECSTANDARD));
2045     PetscCall(VecGetArray(coordinates, &coords));
2046     if (rank == 0) {
2047       coords[0 * dim + 0]  = -ds2;
2048       coords[0 * dim + 1]  = -ds2;
2049       coords[0 * dim + 2]  = 0.0;
2050       coords[1 * dim + 0]  = ds2;
2051       coords[1 * dim + 1]  = -ds2;
2052       coords[1 * dim + 2]  = 0.0;
2053       coords[2 * dim + 0]  = ds2;
2054       coords[2 * dim + 1]  = ds2;
2055       coords[2 * dim + 2]  = 0.0;
2056       coords[3 * dim + 0]  = -ds2;
2057       coords[3 * dim + 1]  = ds2;
2058       coords[3 * dim + 2]  = 0.0;
2059       coords[4 * dim + 0]  = -ds2;
2060       coords[4 * dim + 1]  = -ds2;
2061       coords[4 * dim + 2]  = 1.0;
2062       coords[5 * dim + 0]  = -ds2;
2063       coords[5 * dim + 1]  = ds2;
2064       coords[5 * dim + 2]  = 1.0;
2065       coords[6 * dim + 0]  = ds2;
2066       coords[6 * dim + 1]  = ds2;
2067       coords[6 * dim + 2]  = 1.0;
2068       coords[7 * dim + 0]  = ds2;
2069       coords[7 * dim + 1]  = -ds2;
2070       coords[7 * dim + 2]  = 1.0;
2071       coords[8 * dim + 0]  = dis;
2072       coords[8 * dim + 1]  = -dis;
2073       coords[8 * dim + 2]  = 0.0;
2074       coords[9 * dim + 0]  = dis;
2075       coords[9 * dim + 1]  = dis;
2076       coords[9 * dim + 2]  = 0.0;
2077       coords[10 * dim + 0] = dis;
2078       coords[10 * dim + 1] = -dis;
2079       coords[10 * dim + 2] = 1.0;
2080       coords[11 * dim + 0] = dis;
2081       coords[11 * dim + 1] = dis;
2082       coords[11 * dim + 2] = 1.0;
2083       coords[12 * dim + 0] = -dis;
2084       coords[12 * dim + 1] = dis;
2085       coords[12 * dim + 2] = 0.0;
2086       coords[13 * dim + 0] = -dis;
2087       coords[13 * dim + 1] = dis;
2088       coords[13 * dim + 2] = 1.0;
2089       coords[14 * dim + 0] = -dis;
2090       coords[14 * dim + 1] = -dis;
2091       coords[14 * dim + 2] = 0.0;
2092       coords[15 * dim + 0] = -dis;
2093       coords[15 * dim + 1] = -dis;
2094       coords[15 * dim + 2] = 1.0;
2095       if (periodicZ == DM_BOUNDARY_PERIODIC) {
2096         /* 15 31 19 */ coords[16 * dim + 0] = -ds2;
2097         coords[16 * dim + 1]                = -ds2;
2098         coords[16 * dim + 2]                = 0.5;
2099         /* 16 32 22 */ coords[17 * dim + 0] = ds2;
2100         coords[17 * dim + 1]                = -ds2;
2101         coords[17 * dim + 2]                = 0.5;
2102         /* 17 33 21 */ coords[18 * dim + 0] = ds2;
2103         coords[18 * dim + 1]                = ds2;
2104         coords[18 * dim + 2]                = 0.5;
2105         /* 18 34 20 */ coords[19 * dim + 0] = -ds2;
2106         coords[19 * dim + 1]                = ds2;
2107         coords[19 * dim + 2]                = 0.5;
2108         /* 29 35 30 */ coords[20 * dim + 0] = -dis;
2109         coords[20 * dim + 1]                = -dis;
2110         coords[20 * dim + 2]                = 0.5;
2111         /* 23 36 25 */ coords[21 * dim + 0] = dis;
2112         coords[21 * dim + 1]                = -dis;
2113         coords[21 * dim + 2]                = 0.5;
2114         /* 24 37 26 */ coords[22 * dim + 0] = dis;
2115         coords[22 * dim + 1]                = dis;
2116         coords[22 * dim + 2]                = 0.5;
2117         /* 27 38 28 */ coords[23 * dim + 0] = -dis;
2118         coords[23 * dim + 1]                = dis;
2119         coords[23 * dim + 2]                = 0.5;
2120       }
2121     }
2122     PetscCall(VecRestoreArray(coordinates, &coords));
2123     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2124     PetscCall(VecDestroy(&coordinates));
2125   }
2126   /* Create periodicity */
2127   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
2128     PetscReal L[3]       = {-1., -1., 0.};
2129     PetscReal maxCell[3] = {-1., -1., 0.};
2130     PetscReal lower[3]   = {0.0, 0.0, 0.0};
2131     PetscReal upper[3]   = {1.0, 1.0, 1.5};
2132     PetscInt  numZCells  = 3;
2133 
2134     L[2]       = upper[2] - lower[2];
2135     maxCell[2] = 1.1 * (L[2] / numZCells);
2136     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
2137   }
2138   {
2139     DM          cdm;
2140     PetscDS     cds;
2141     PetscScalar c[2] = {1.0, 1.0};
2142 
2143     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToCylinder));
2144     PetscCall(DMGetCoordinateDM(dm, &cdm));
2145     PetscCall(DMGetDS(cdm, &cds));
2146     PetscCall(PetscDSSetConstants(cds, 2, c));
2147   }
2148   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2149 
2150   /* Wait for coordinate creation before doing in-place modification */
2151   PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2152   PetscFunctionReturn(PETSC_SUCCESS);
2153 }
2154 
2155 /*@
2156   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
2157 
2158   Collective
2159 
2160   Input Parameters:
2161 + comm      - The communicator for the `DM` object
2162 - periodicZ - The boundary type for the Z direction
2163 
2164   Output Parameter:
2165 . dm - The `DM` object
2166 
2167   Level: beginner
2168 
2169   Note:
2170   Here is the output numbering looking from the bottom of the cylinder\:
2171 .vb
2172        17-----14
2173         |     |
2174         |  2  |
2175         |     |
2176  17-----8-----7-----14
2177   |     |     |     |
2178   |  3  |  0  |  1  |
2179   |     |     |     |
2180  19-----5-----6-----13
2181         |     |
2182         |  4  |
2183         |     |
2184        19-----13
2185 
2186  and up through the top
2187 
2188        18-----16
2189         |     |
2190         |  2  |
2191         |     |
2192  18----10----11-----16
2193   |     |     |     |
2194   |  3  |  0  |  1  |
2195   |     |     |     |
2196  20-----9----12-----15
2197         |     |
2198         |  4  |
2199         |     |
2200        20-----15
2201 .ve
2202 
2203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2204 @*/
2205 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, DM *dm)
2206 {
2207   PetscFunctionBegin;
2208   PetscAssertPointer(dm, 3);
2209   PetscCall(DMCreate(comm, dm));
2210   PetscCall(DMSetType(*dm, DMPLEX));
2211   PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ));
2212   PetscFunctionReturn(PETSC_SUCCESS);
2213 }
2214 
2215 static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate)
2216 {
2217   const PetscInt dim = 3;
2218   PetscInt       numCells, numVertices, v;
2219   PetscMPIInt    rank;
2220 
2221   PetscFunctionBegin;
2222   PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n);
2223   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2224   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2225   PetscCall(DMSetDimension(dm, dim));
2226   /* Must create the celltype label here so that we do not automatically try to compute the types */
2227   PetscCall(DMCreateLabel(dm, "celltype"));
2228   /* Create topology */
2229   {
2230     PetscInt cone[6], c;
2231 
2232     numCells    = rank == 0 ? n : 0;
2233     numVertices = rank == 0 ? 2 * (n + 1) : 0;
2234     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
2235     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
2236     PetscCall(DMSetUp(dm));
2237     for (c = 0; c < numCells; c++) {
2238       cone[0] = c + n * 1;
2239       cone[1] = (c + 1) % n + n * 1;
2240       cone[2] = 0 + 3 * n;
2241       cone[3] = c + n * 2;
2242       cone[4] = (c + 1) % n + n * 2;
2243       cone[5] = 1 + 3 * n;
2244       PetscCall(DMPlexSetCone(dm, c, cone));
2245       PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR));
2246     }
2247     PetscCall(DMPlexSymmetrize(dm));
2248     PetscCall(DMPlexStratify(dm));
2249   }
2250   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT));
2251   /* Create cylinder geometry */
2252   {
2253     Vec          coordinates;
2254     PetscSection coordSection;
2255     PetscScalar *coords;
2256     PetscInt     coordSize, c;
2257 
2258     /* Build coordinates */
2259     PetscCall(DMGetCoordinateSection(dm, &coordSection));
2260     PetscCall(PetscSectionSetNumFields(coordSection, 1));
2261     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2262     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
2263     for (v = numCells; v < numCells + numVertices; ++v) {
2264       PetscCall(PetscSectionSetDof(coordSection, v, dim));
2265       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2266     }
2267     PetscCall(PetscSectionSetUp(coordSection));
2268     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2269     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2270     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2271     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2272     PetscCall(VecSetBlockSize(coordinates, dim));
2273     PetscCall(VecSetType(coordinates, VECSTANDARD));
2274     PetscCall(VecGetArray(coordinates, &coords));
2275     for (c = 0; c < numCells; c++) {
2276       coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2277       coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2278       coords[(c + 0 * n) * dim + 2] = 1.0;
2279       coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
2280       coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
2281       coords[(c + 1 * n) * dim + 2] = 0.0;
2282     }
2283     if (rank == 0) {
2284       coords[(2 * n + 0) * dim + 0] = 0.0;
2285       coords[(2 * n + 0) * dim + 1] = 0.0;
2286       coords[(2 * n + 0) * dim + 2] = 1.0;
2287       coords[(2 * n + 1) * dim + 0] = 0.0;
2288       coords[(2 * n + 1) * dim + 1] = 0.0;
2289       coords[(2 * n + 1) * dim + 2] = 0.0;
2290     }
2291     PetscCall(VecRestoreArray(coordinates, &coords));
2292     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2293     PetscCall(VecDestroy(&coordinates));
2294   }
2295   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2296   /* Interpolate */
2297   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2298   PetscFunctionReturn(PETSC_SUCCESS);
2299 }
2300 
2301 /*@
2302   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
2303 
2304   Collective
2305 
2306   Input Parameters:
2307 + comm        - The communicator for the `DM` object
2308 . n           - The number of wedges around the origin
2309 - interpolate - Create edges and faces
2310 
2311   Output Parameter:
2312 . dm - The `DM` object
2313 
2314   Level: beginner
2315 
2316 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
2317 @*/
2318 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
2319 {
2320   PetscFunctionBegin;
2321   PetscAssertPointer(dm, 4);
2322   PetscCall(DMCreate(comm, dm));
2323   PetscCall(DMSetType(*dm, DMPLEX));
2324   PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate));
2325   PetscFunctionReturn(PETSC_SUCCESS);
2326 }
2327 
2328 static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2329 {
2330   PetscReal prod = 0.0;
2331   PetscInt  i;
2332   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
2333   return PetscSqrtReal(prod);
2334 }
2335 
2336 static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
2337 {
2338   PetscReal prod = 0.0;
2339   PetscInt  i;
2340   for (i = 0; i < dim; ++i) prod += x[i] * y[i];
2341   return prod;
2342 }
2343 
2344 /* The first constant is the sphere radius */
2345 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[])
2346 {
2347   PetscReal r     = PetscRealPart(constants[0]);
2348   PetscReal norm2 = 0.0, fac;
2349   PetscInt  n     = uOff[1] - uOff[0], d;
2350 
2351   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
2352   fac = r / PetscSqrtReal(norm2);
2353   for (d = 0; d < n; ++d) f0[d] = u[d] * fac;
2354 }
2355 
2356 static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R)
2357 {
2358   const PetscInt embedDim = dim + 1;
2359   PetscSection   coordSection;
2360   Vec            coordinates;
2361   PetscScalar   *coords;
2362   PetscReal     *coordsIn;
2363   PetscInt       numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e;
2364   PetscMPIInt    rank;
2365 
2366   PetscFunctionBegin;
2367   PetscValidLogicalCollectiveBool(dm, simplex, 3);
2368   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
2369   PetscCall(DMSetDimension(dm, dim));
2370   PetscCall(DMSetCoordinateDim(dm, dim + 1));
2371   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
2372   switch (dim) {
2373   case 1:
2374     numCells = 16;
2375     numVerts = numCells;
2376 
2377     // Build Topology
2378     PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2379     for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2380     PetscCall(DMSetUp(dm));
2381     for (PetscInt c = 0; c < numCells; ++c) {
2382       PetscInt cone[2];
2383 
2384       cone[0] = c + numCells;
2385       cone[1] = (c + 1) % numVerts + numCells;
2386       PetscCall(DMPlexSetCone(dm, c, cone));
2387     }
2388     PetscCall(DMPlexSymmetrize(dm));
2389     PetscCall(DMPlexStratify(dm));
2390     PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn));
2391     for (PetscInt v = 0; v < numVerts; ++v) {
2392       const PetscReal rad = 2. * PETSC_PI * v / numVerts;
2393 
2394       coordsIn[v * embedDim + 0] = PetscCosReal(rad);
2395       coordsIn[v * embedDim + 1] = PetscSinReal(rad);
2396     }
2397     break;
2398   case 2:
2399     if (simplex) {
2400       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI);
2401       const PetscReal edgeLen   = 2.0 / (1.0 + PETSC_PHI) * (R / radius);
2402       const PetscInt  degree    = 5;
2403       PetscReal       vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)};
2404       PetscInt        s[3]      = {1, 1, 1};
2405       PetscInt        cone[3];
2406       PetscInt       *graph;
2407 
2408       vertex[0] *= R / radius;
2409       vertex[1] *= R / radius;
2410       vertex[2] *= R / radius;
2411       numCells    = rank == 0 ? 20 : 0;
2412       numVerts    = rank == 0 ? 12 : 0;
2413       firstVertex = numCells;
2414       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of
2415 
2416            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
2417 
2418          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2419          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
2420       */
2421       /* Construct vertices */
2422       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2423       if (rank == 0) {
2424         for (PetscInt p = 0, i = 0; p < embedDim; ++p) {
2425           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2426             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2427               for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim];
2428               ++i;
2429             }
2430           }
2431         }
2432       }
2433       /* Construct graph */
2434       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2435       for (PetscInt i = 0; i < numVerts; ++i) {
2436         PetscInt k = 0;
2437         for (PetscInt j = 0; j < numVerts; ++j) {
2438           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2439             graph[i * numVerts + j] = 1;
2440             ++k;
2441           }
2442         }
2443         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2444       }
2445       /* Build Topology */
2446       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2447       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2448       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2449       /* Cells */
2450       for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
2451         for (PetscInt j = 0; j < i; ++j) {
2452           for (PetscInt k = 0; k < j; ++k) {
2453             if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) {
2454               cone[0] = firstVertex + i;
2455               cone[1] = firstVertex + j;
2456               cone[2] = firstVertex + k;
2457               /* Check orientation */
2458               {
2459                 const PetscInt epsilon[3][3][3] = {
2460                   {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
2461                   {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
2462                   {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
2463                 };
2464                 PetscReal normal[3];
2465                 PetscInt  e, f;
2466 
2467                 for (d = 0; d < embedDim; ++d) {
2468                   normal[d] = 0.0;
2469                   for (e = 0; e < embedDim; ++e) {
2470                     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]);
2471                   }
2472                 }
2473                 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2474                   PetscInt tmp = cone[1];
2475                   cone[1]      = cone[2];
2476                   cone[2]      = tmp;
2477                 }
2478               }
2479               PetscCall(DMPlexSetCone(dm, c++, cone));
2480             }
2481           }
2482         }
2483       }
2484       PetscCall(DMPlexSymmetrize(dm));
2485       PetscCall(DMPlexStratify(dm));
2486       PetscCall(PetscFree(graph));
2487     } else {
2488       /*
2489         12-21--13
2490          |     |
2491         25  4  24
2492          |     |
2493   12-25--9-16--8-24--13
2494    |     |     |     |
2495   23  5 17  0 15  3  22
2496    |     |     |     |
2497   10-20--6-14--7-19--11
2498          |     |
2499         20  1  19
2500          |     |
2501         10-18--11
2502          |     |
2503         23  2  22
2504          |     |
2505         12-21--13
2506        */
2507       PetscInt cone[4], ornt[4];
2508 
2509       numCells    = rank == 0 ? 6 : 0;
2510       numEdges    = rank == 0 ? 12 : 0;
2511       numVerts    = rank == 0 ? 8 : 0;
2512       firstVertex = numCells;
2513       firstEdge   = numCells + numVerts;
2514       /* Build Topology */
2515       PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts));
2516       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4));
2517       for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
2518       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2519       if (rank == 0) {
2520         /* Cell 0 */
2521         cone[0] = 14;
2522         cone[1] = 15;
2523         cone[2] = 16;
2524         cone[3] = 17;
2525         PetscCall(DMPlexSetCone(dm, 0, cone));
2526         ornt[0] = 0;
2527         ornt[1] = 0;
2528         ornt[2] = 0;
2529         ornt[3] = 0;
2530         PetscCall(DMPlexSetConeOrientation(dm, 0, ornt));
2531         /* Cell 1 */
2532         cone[0] = 18;
2533         cone[1] = 19;
2534         cone[2] = 14;
2535         cone[3] = 20;
2536         PetscCall(DMPlexSetCone(dm, 1, cone));
2537         ornt[0] = 0;
2538         ornt[1] = 0;
2539         ornt[2] = -1;
2540         ornt[3] = 0;
2541         PetscCall(DMPlexSetConeOrientation(dm, 1, ornt));
2542         /* Cell 2 */
2543         cone[0] = 21;
2544         cone[1] = 22;
2545         cone[2] = 18;
2546         cone[3] = 23;
2547         PetscCall(DMPlexSetCone(dm, 2, cone));
2548         ornt[0] = 0;
2549         ornt[1] = 0;
2550         ornt[2] = -1;
2551         ornt[3] = 0;
2552         PetscCall(DMPlexSetConeOrientation(dm, 2, ornt));
2553         /* Cell 3 */
2554         cone[0] = 19;
2555         cone[1] = 22;
2556         cone[2] = 24;
2557         cone[3] = 15;
2558         PetscCall(DMPlexSetCone(dm, 3, cone));
2559         ornt[0] = -1;
2560         ornt[1] = -1;
2561         ornt[2] = 0;
2562         ornt[3] = -1;
2563         PetscCall(DMPlexSetConeOrientation(dm, 3, ornt));
2564         /* Cell 4 */
2565         cone[0] = 16;
2566         cone[1] = 24;
2567         cone[2] = 21;
2568         cone[3] = 25;
2569         PetscCall(DMPlexSetCone(dm, 4, cone));
2570         ornt[0] = -1;
2571         ornt[1] = -1;
2572         ornt[2] = -1;
2573         ornt[3] = 0;
2574         PetscCall(DMPlexSetConeOrientation(dm, 4, ornt));
2575         /* Cell 5 */
2576         cone[0] = 20;
2577         cone[1] = 17;
2578         cone[2] = 25;
2579         cone[3] = 23;
2580         PetscCall(DMPlexSetCone(dm, 5, cone));
2581         ornt[0] = -1;
2582         ornt[1] = -1;
2583         ornt[2] = -1;
2584         ornt[3] = -1;
2585         PetscCall(DMPlexSetConeOrientation(dm, 5, ornt));
2586         /* Edges */
2587         cone[0] = 6;
2588         cone[1] = 7;
2589         PetscCall(DMPlexSetCone(dm, 14, cone));
2590         cone[0] = 7;
2591         cone[1] = 8;
2592         PetscCall(DMPlexSetCone(dm, 15, cone));
2593         cone[0] = 8;
2594         cone[1] = 9;
2595         PetscCall(DMPlexSetCone(dm, 16, cone));
2596         cone[0] = 9;
2597         cone[1] = 6;
2598         PetscCall(DMPlexSetCone(dm, 17, cone));
2599         cone[0] = 10;
2600         cone[1] = 11;
2601         PetscCall(DMPlexSetCone(dm, 18, cone));
2602         cone[0] = 11;
2603         cone[1] = 7;
2604         PetscCall(DMPlexSetCone(dm, 19, cone));
2605         cone[0] = 6;
2606         cone[1] = 10;
2607         PetscCall(DMPlexSetCone(dm, 20, cone));
2608         cone[0] = 12;
2609         cone[1] = 13;
2610         PetscCall(DMPlexSetCone(dm, 21, cone));
2611         cone[0] = 13;
2612         cone[1] = 11;
2613         PetscCall(DMPlexSetCone(dm, 22, cone));
2614         cone[0] = 10;
2615         cone[1] = 12;
2616         PetscCall(DMPlexSetCone(dm, 23, cone));
2617         cone[0] = 13;
2618         cone[1] = 8;
2619         PetscCall(DMPlexSetCone(dm, 24, cone));
2620         cone[0] = 12;
2621         cone[1] = 9;
2622         PetscCall(DMPlexSetCone(dm, 25, cone));
2623       }
2624       PetscCall(DMPlexSymmetrize(dm));
2625       PetscCall(DMPlexStratify(dm));
2626       /* Build coordinates */
2627       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2628       if (rank == 0) {
2629         coordsIn[0 * embedDim + 0] = -R;
2630         coordsIn[0 * embedDim + 1] = R;
2631         coordsIn[0 * embedDim + 2] = -R;
2632         coordsIn[1 * embedDim + 0] = R;
2633         coordsIn[1 * embedDim + 1] = R;
2634         coordsIn[1 * embedDim + 2] = -R;
2635         coordsIn[2 * embedDim + 0] = R;
2636         coordsIn[2 * embedDim + 1] = -R;
2637         coordsIn[2 * embedDim + 2] = -R;
2638         coordsIn[3 * embedDim + 0] = -R;
2639         coordsIn[3 * embedDim + 1] = -R;
2640         coordsIn[3 * embedDim + 2] = -R;
2641         coordsIn[4 * embedDim + 0] = -R;
2642         coordsIn[4 * embedDim + 1] = R;
2643         coordsIn[4 * embedDim + 2] = R;
2644         coordsIn[5 * embedDim + 0] = R;
2645         coordsIn[5 * embedDim + 1] = R;
2646         coordsIn[5 * embedDim + 2] = R;
2647         coordsIn[6 * embedDim + 0] = -R;
2648         coordsIn[6 * embedDim + 1] = -R;
2649         coordsIn[6 * embedDim + 2] = R;
2650         coordsIn[7 * embedDim + 0] = R;
2651         coordsIn[7 * embedDim + 1] = -R;
2652         coordsIn[7 * embedDim + 2] = R;
2653       }
2654     }
2655     break;
2656   case 3:
2657     if (simplex) {
2658       const PetscReal edgeLen         = 1.0 / PETSC_PHI;
2659       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
2660       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
2661       PetscReal       vertexC[4]      = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0};
2662       const PetscInt  degree          = 12;
2663       PetscInt        s[4]            = {1, 1, 1};
2664       PetscInt        evenPerm[12][4] = {
2665         {0, 1, 2, 3},
2666         {0, 2, 3, 1},
2667         {0, 3, 1, 2},
2668         {1, 0, 3, 2},
2669         {1, 2, 0, 3},
2670         {1, 3, 2, 0},
2671         {2, 0, 1, 3},
2672         {2, 1, 3, 0},
2673         {2, 3, 0, 1},
2674         {3, 0, 2, 1},
2675         {3, 1, 0, 2},
2676         {3, 2, 1, 0}
2677       };
2678       PetscInt  cone[4];
2679       PetscInt *graph, p, i, j, k, l;
2680 
2681       vertexA[0] *= R;
2682       vertexA[1] *= R;
2683       vertexA[2] *= R;
2684       vertexA[3] *= R;
2685       vertexB[0] *= R;
2686       vertexB[1] *= R;
2687       vertexB[2] *= R;
2688       vertexB[3] *= R;
2689       vertexC[0] *= R;
2690       vertexC[1] *= R;
2691       vertexC[2] *= R;
2692       vertexC[3] *= R;
2693       numCells    = rank == 0 ? 600 : 0;
2694       numVerts    = rank == 0 ? 120 : 0;
2695       firstVertex = numCells;
2696       /* Use the 600-cell, which for a unit sphere has coordinates which are
2697 
2698            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
2699                (\pm 1,    0,       0,      0)  all cyclic permutations   8
2700            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
2701 
2702          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2703          length is then given by 1/\phi = 0.61803.
2704 
2705          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
2706          http://mathworld.wolfram.com/600-Cell.html
2707       */
2708       /* Construct vertices */
2709       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
2710       i = 0;
2711       if (rank == 0) {
2712         for (s[0] = -1; s[0] < 2; s[0] += 2) {
2713           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2714             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2715               for (s[3] = -1; s[3] < 2; s[3] += 2) {
2716                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d];
2717                 ++i;
2718               }
2719             }
2720           }
2721         }
2722         for (p = 0; p < embedDim; ++p) {
2723           s[1] = s[2] = s[3] = 1;
2724           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2725             for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim];
2726             ++i;
2727           }
2728         }
2729         for (p = 0; p < 12; ++p) {
2730           s[3] = 1;
2731           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2732             for (s[1] = -1; s[1] < 2; s[1] += 2) {
2733               for (s[2] = -1; s[2] < 2; s[2] += 2) {
2734                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]];
2735                 ++i;
2736               }
2737             }
2738           }
2739         }
2740       }
2741       PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts);
2742       /* Construct graph */
2743       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
2744       for (i = 0; i < numVerts; ++i) {
2745         for (j = 0, k = 0; j < numVerts; ++j) {
2746           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
2747             graph[i * numVerts + j] = 1;
2748             ++k;
2749           }
2750         }
2751         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
2752       }
2753       /* Build Topology */
2754       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
2755       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
2756       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
2757       /* Cells */
2758       if (rank == 0) {
2759         for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
2760           for (j = 0; j < i; ++j) {
2761             for (k = 0; k < j; ++k) {
2762               for (l = 0; l < k; ++l) {
2763                 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]) {
2764                   cone[0] = firstVertex + i;
2765                   cone[1] = firstVertex + j;
2766                   cone[2] = firstVertex + k;
2767                   cone[3] = firstVertex + l;
2768                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
2769                   {
2770                     const PetscInt epsilon[4][4][4][4] = {
2771                       {{{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}}},
2772 
2773                       {{{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}}},
2774 
2775                       {{{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}}},
2776 
2777                       {{{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}} }
2778                     };
2779                     PetscReal normal[4];
2780                     PetscInt  e, f, g;
2781 
2782                     for (d = 0; d < embedDim; ++d) {
2783                       normal[d] = 0.0;
2784                       for (e = 0; e < embedDim; ++e) {
2785                         for (f = 0; f < embedDim; ++f) {
2786                           for (g = 0; g < embedDim; ++g) {
2787                             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]);
2788                           }
2789                         }
2790                       }
2791                     }
2792                     if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
2793                       PetscInt tmp = cone[1];
2794                       cone[1]      = cone[2];
2795                       cone[2]      = tmp;
2796                     }
2797                   }
2798                   PetscCall(DMPlexSetCone(dm, c++, cone));
2799                 }
2800               }
2801             }
2802           }
2803         }
2804       }
2805       PetscCall(DMPlexSymmetrize(dm));
2806       PetscCall(DMPlexStratify(dm));
2807       PetscCall(PetscFree(graph));
2808     }
2809     break;
2810   default:
2811     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim);
2812   }
2813   /* Create coordinates */
2814   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2815   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2816   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim));
2817   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts));
2818   for (v = firstVertex; v < firstVertex + numVerts; ++v) {
2819     PetscCall(PetscSectionSetDof(coordSection, v, embedDim));
2820     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim));
2821   }
2822   PetscCall(PetscSectionSetUp(coordSection));
2823   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
2824   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
2825   PetscCall(VecSetBlockSize(coordinates, embedDim));
2826   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2827   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2828   PetscCall(VecSetType(coordinates, VECSTANDARD));
2829   PetscCall(VecGetArray(coordinates, &coords));
2830   for (v = 0; v < numVerts; ++v)
2831     for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d];
2832   PetscCall(VecRestoreArray(coordinates, &coords));
2833   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2834   PetscCall(VecDestroy(&coordinates));
2835   PetscCall(PetscFree(coordsIn));
2836   {
2837     DM          cdm;
2838     PetscDS     cds;
2839     PetscScalar c = R;
2840 
2841     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, snapToSphere));
2842     PetscCall(DMGetCoordinateDM(dm, &cdm));
2843     PetscCall(DMGetDS(cdm, &cds));
2844     PetscCall(PetscDSSetConstants(cds, 1, &c));
2845   }
2846   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
2847   /* Wait for coordinate creation before doing in-place modification */
2848   if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
2849   PetscFunctionReturn(PETSC_SUCCESS);
2850 }
2851 
2852 typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]);
2853 
2854 /*
2855  The Schwarz P implicit surface is
2856 
2857      f(x) = cos(x0) + cos(x1) + cos(x2) = 0
2858 */
2859 static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2860 {
2861   PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)};
2862   PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)};
2863   f[0]           = c[0] + c[1] + c[2];
2864   for (PetscInt i = 0; i < 3; i++) {
2865     grad[i] = PETSC_PI * g[i];
2866     for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.;
2867   }
2868 }
2869 
2870 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2871 static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2872 {
2873   for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI);
2874   return PETSC_SUCCESS;
2875 }
2876 
2877 /*
2878  The Gyroid implicit surface is
2879 
2880  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)
2881 
2882 */
2883 static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
2884 {
2885   PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))};
2886   PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))};
2887   f[0]           = s[0] * c[1] + s[1] * c[2] + s[2] * c[0];
2888   grad[0]        = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2889   grad[1]        = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2890   grad[2]        = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2891   hess[0][0]     = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]);
2892   hess[0][1]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2893   hess[0][2]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2894   hess[1][0]     = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]);
2895   hess[1][1]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2896   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
2897   hess[2][0]     = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]);
2898   hess[2][1]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
2899   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
2900 }
2901 
2902 // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
2903 static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
2904 {
2905   PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))};
2906   PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))};
2907   u[0]           = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
2908   u[1]           = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
2909   u[2]           = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
2910   return PETSC_SUCCESS;
2911 }
2912 
2913 /*
2914    We wish to solve
2915 
2916          min_y || y - x ||^2  subject to f(y) = 0
2917 
2918    Let g(y) = grad(f).  The minimization problem is equivalent to asking to satisfy
2919    f(y) = 0 and (y-x) is parallel to g(y).  We do this by using Householder QR to obtain a basis for the
2920    tangent space and ask for both components in the tangent space to be zero.
2921 
2922    Take g to be a column vector and compute the "full QR" factorization Q R = g,
2923    where Q = I - 2 n n^T is a symmetric orthogonal matrix.
2924    The first column of Q is parallel to g so the remaining two columns span the null space.
2925    Let Qn = Q[:,1:] be those remaining columns.  Then Qn Qn^T is an orthogonal projector into the tangent space.
2926    Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries.
2927    In total, we have a system of 3 equations in 3 unknowns:
2928 
2929      f(y) = 0                       1 equation
2930      Qn^T (y - x) = 0               2 equations
2931 
2932    Here, we compute the residual and Jacobian of this system.
2933 */
2934 static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[])
2935 {
2936   PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])};
2937   PetscReal d[3]     = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])};
2938   PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign;
2939   PetscReal n_y[3][3] = {
2940     {0, 0, 0},
2941     {0, 0, 0},
2942     {0, 0, 0}
2943   };
2944 
2945   feval(yreal, &f, grad, n_y);
2946 
2947   for (PetscInt i = 0; i < 3; i++) n[i] = grad[i];
2948   norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2949   for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i];
2950 
2951   // Define the Householder reflector
2952   sign = n[0] >= 0 ? 1. : -1.;
2953   n[0] += norm * sign;
2954   for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign;
2955 
2956   norm      = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
2957   norm_y[0] = 1. / norm * (n[0] * n_y[0][0]);
2958   norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]);
2959   norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]);
2960 
2961   for (PetscInt i = 0; i < 3; i++) {
2962     n[i] /= norm;
2963     for (PetscInt j = 0; j < 3; j++) {
2964       // note that n[i] is n_old[i]/norm when executing the code below
2965       n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j];
2966     }
2967   }
2968 
2969   nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2];
2970   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];
2971 
2972   res[0] = f;
2973   res[1] = d[1] - 2 * n[1] * nd;
2974   res[2] = d[2] - 2 * n[2] * nd;
2975   // J[j][i] is J_{ij} (column major)
2976   for (PetscInt j = 0; j < 3; j++) {
2977     J[0 + j * 3] = grad[j];
2978     J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]);
2979     J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]);
2980   }
2981 }
2982 
2983 /*
2984    Project x to the nearest point on the implicit surface using Newton's method.
2985 */
2986 static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[])
2987 {
2988   PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess
2989 
2990   PetscFunctionBegin;
2991   for (PetscInt iter = 0; iter < 10; iter++) {
2992     PetscScalar res[3], J[9];
2993     PetscReal   resnorm;
2994     TPSNearestPointResJac(feval, x, y, res, J);
2995     resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2])));
2996     if (0) { // Turn on this monitor if you need to confirm quadratic convergence
2997       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])));
2998     }
2999     if (resnorm < PETSC_SMALL) break;
3000 
3001     // Take the Newton step
3002     PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL));
3003     PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res);
3004   }
3005   for (PetscInt i = 0; i < 3; i++) x[i] = y[i];
3006   PetscFunctionReturn(PETSC_SUCCESS);
3007 }
3008 
3009 const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL};
3010 
3011 static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness)
3012 {
3013   PetscMPIInt rank;
3014   PetscInt    topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0;
3015   PetscInt(*edges)[2] = NULL, *edgeSets = NULL;
3016   PetscInt           *cells_flat = NULL;
3017   PetscReal          *vtxCoords  = NULL;
3018   TPSEvaluateFunc     evalFunc   = NULL;
3019   PetscSimplePointFn *normalFunc = NULL;
3020   DMLabel             label;
3021 
3022   PetscFunctionBegin;
3023   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
3024   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3025   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);
3026   switch (tpstype) {
3027   case DMPLEX_TPS_SCHWARZ_P:
3028     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");
3029     if (rank == 0) {
3030       PetscInt(*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn]
3031       PetscInt  Njunctions = 0, Ncuts = 0, Npipes[3], vcount;
3032       PetscReal L = 1;
3033 
3034       Npipes[0]   = (extent[0] + 1) * extent[1] * extent[2];
3035       Npipes[1]   = extent[0] * (extent[1] + 1) * extent[2];
3036       Npipes[2]   = extent[0] * extent[1] * (extent[2] + 1);
3037       Njunctions  = extent[0] * extent[1] * extent[2];
3038       Ncuts       = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]);
3039       numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions;
3040       PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords));
3041       PetscCall(PetscMalloc1(Njunctions, &cells));
3042       PetscCall(PetscMalloc1(Ncuts * 4, &edges));
3043       PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets));
3044       // x-normal pipes
3045       vcount = 0;
3046       for (PetscInt i = 0; i < extent[0] + 1; i++) {
3047         for (PetscInt j = 0; j < extent[1]; j++) {
3048           for (PetscInt k = 0; k < extent[2]; k++) {
3049             for (PetscInt l = 0; l < 4; l++) {
3050               vtxCoords[vcount++] = (2 * i - 1) * L;
3051               vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3052               vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3053             }
3054           }
3055         }
3056       }
3057       // y-normal pipes
3058       for (PetscInt i = 0; i < extent[0]; i++) {
3059         for (PetscInt j = 0; j < extent[1] + 1; j++) {
3060           for (PetscInt k = 0; k < extent[2]; k++) {
3061             for (PetscInt l = 0; l < 4; l++) {
3062               vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3063               vtxCoords[vcount++] = (2 * j - 1) * L;
3064               vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3065             }
3066           }
3067         }
3068       }
3069       // z-normal pipes
3070       for (PetscInt i = 0; i < extent[0]; i++) {
3071         for (PetscInt j = 0; j < extent[1]; j++) {
3072           for (PetscInt k = 0; k < extent[2] + 1; k++) {
3073             for (PetscInt l = 0; l < 4; l++) {
3074               vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3075               vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3076               vtxCoords[vcount++] = (2 * k - 1) * L;
3077             }
3078           }
3079         }
3080       }
3081       // junctions
3082       for (PetscInt i = 0; i < extent[0]; i++) {
3083         for (PetscInt j = 0; j < extent[1]; j++) {
3084           for (PetscInt k = 0; k < extent[2]; k++) {
3085             const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8;
3086             PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count");
3087             for (PetscInt ii = 0; ii < 2; ii++) {
3088               for (PetscInt jj = 0; jj < 2; jj++) {
3089                 for (PetscInt kk = 0; kk < 2; kk++) {
3090                   double Ls           = (1 - sqrt(2) / 4) * L;
3091                   vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls;
3092                   vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls;
3093                   vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls;
3094                 }
3095               }
3096             }
3097             const PetscInt jfaces[3][2][4] = {
3098               {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned
3099               {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned
3100               {{6, 2, 0, 4}, {7, 3, 1, 5}}  // z-aligned
3101             };
3102             const PetscInt pipe_lo[3] = {// vertex numbers of pipes
3103                                          ((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};
3104             const PetscInt pipe_hi[3] = {// vertex numbers of pipes
3105                                          (((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};
3106             for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z
3107               const PetscInt ijk[3] = {i, j, k};
3108               for (PetscInt l = 0; l < 4; l++) { // rotations
3109                 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l;
3110                 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l];
3111                 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4];
3112                 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4;
3113                 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l];
3114                 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l;
3115                 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4;
3116                 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4];
3117                 if (ijk[dir] == 0) {
3118                   edges[numEdges][0] = pipe_lo[dir] + l;
3119                   edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4;
3120                   edgeSets[numEdges] = dir * 2 + 1;
3121                   numEdges++;
3122                 }
3123                 if (ijk[dir] + 1 == extent[dir]) {
3124                   edges[numEdges][0] = pipe_hi[dir] + l;
3125                   edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4;
3126                   edgeSets[numEdges] = dir * 2 + 2;
3127                   numEdges++;
3128                 }
3129               }
3130             }
3131           }
3132         }
3133       }
3134       PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts);
3135       numFaces   = 24 * Njunctions;
3136       cells_flat = cells[0][0][0];
3137     }
3138     evalFunc   = TPSEvaluate_SchwarzP;
3139     normalFunc = TPSExtrudeNormalFunc_SchwarzP;
3140     break;
3141   case DMPLEX_TPS_GYROID:
3142     if (rank == 0) {
3143       // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set
3144       //
3145       //     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)
3146       //
3147       // on the cell [0,2]^3.
3148       //
3149       // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2].
3150       // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins
3151       // like a boomerang:
3152       //
3153       //     z = 0          z = 1/4        z = 1/2        z = 3/4     //
3154       //     -----          -------        -------        -------     //
3155       //                                                              //
3156       //     +       +      +       +      +       +      +   \   +   //
3157       //      \                                   /            \      //
3158       //       \            `-_   _-'            /              }     //
3159       //        *-_            `-'            _-'              /      //
3160       //     +     `-+      +       +      +-'     +      +   /   +   //
3161       //                                                              //
3162       //                                                              //
3163       //     z = 1          z = 5/4        z = 3/2        z = 7/4     //
3164       //     -----          -------        -------        -------     //
3165       //                                                              //
3166       //     +-_     +      +       +      +     _-+      +   /   +   //
3167       //        `-_            _-_            _-`            /        //
3168       //           \        _-'   `-_        /              {         //
3169       //            \                       /                \        //
3170       //     +       +      +       +      +       +      +   \   +   //
3171       //
3172       //
3173       // This course mesh approximates each of these slices by two line segments,
3174       // and then connects the segments in consecutive layers with quadrilateral faces.
3175       // All of the end points of the segments are multiples of 1/4 except for the
3176       // point * in the picture for z = 0 above and the similar points in other layers.
3177       // That point is at (gamma, gamma, 0), where gamma is calculated below.
3178       //
3179       // The column  [1,2]x[1,2]x[0,2] looks the same as this column;
3180       // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images.
3181       //
3182       // As for how this method turned into the names given to the vertices:
3183       // that was not systematic, it was just the way it worked out in my handwritten notes.
3184 
3185       PetscInt facesPerBlock = 64;
3186       PetscInt vertsPerBlock = 56;
3187       PetscInt extentPlus[3];
3188       PetscInt numBlocks, numBlocksPlus;
3189       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;
3190       const PetscInt pattern[64][4] = {
3191         /* face to vertex within the coarse discretization of a single gyroid block */
3192         /* layer 0 */
3193         {A,           C,           K,           G          },
3194         {C,           B,           II,          K          },
3195         {D,           A,           H,           L          },
3196         {B + 56 * 1,  D,           L,           J          },
3197         {E,           B + 56 * 1,  J,           N          },
3198         {A + 56 * 2,  E,           N,           H + 56 * 2 },
3199         {F,           A + 56 * 2,  G + 56 * 2,  M          },
3200         {B,           F,           M,           II         },
3201         /* layer 1 */
3202         {G,           K,           Q,           O          },
3203         {K,           II,          P,           Q          },
3204         {L,           H,           O + 56 * 1,  R          },
3205         {J,           L,           R,           P          },
3206         {N,           J,           P,           S          },
3207         {H + 56 * 2,  N,           S,           O + 56 * 3 },
3208         {M,           G + 56 * 2,  O + 56 * 2,  T          },
3209         {II,          M,           T,           P          },
3210         /* layer 2 */
3211         {O,           Q,           Y,           U          },
3212         {Q,           P,           W,           Y          },
3213         {R,           O + 56 * 1,  U + 56 * 1,  Ap         },
3214         {P,           R,           Ap,          W          },
3215         {S,           P,           X,           Bp         },
3216         {O + 56 * 3,  S,           Bp,          V + 56 * 1 },
3217         {T,           O + 56 * 2,  V,           Z          },
3218         {P,           T,           Z,           X          },
3219         /* layer 3 */
3220         {U,           Y,           Ep,          Dp         },
3221         {Y,           W,           Cp,          Ep         },
3222         {Ap,          U + 56 * 1,  Dp + 56 * 1, Gp         },
3223         {W,           Ap,          Gp,          Cp         },
3224         {Bp,          X,           Cp + 56 * 2, Fp         },
3225         {V + 56 * 1,  Bp,          Fp,          Dp + 56 * 1},
3226         {Z,           V,           Dp,          Hp         },
3227         {X,           Z,           Hp,          Cp + 56 * 2},
3228         /* layer 4 */
3229         {Dp,          Ep,          Mp,          Kp         },
3230         {Ep,          Cp,          Ip,          Mp         },
3231         {Gp,          Dp + 56 * 1, Lp,          Np         },
3232         {Cp,          Gp,          Np,          Jp         },
3233         {Fp,          Cp + 56 * 2, Jp + 56 * 2, Pp         },
3234         {Dp + 56 * 1, Fp,          Pp,          Lp         },
3235         {Hp,          Dp,          Kp,          Op         },
3236         {Cp + 56 * 2, Hp,          Op,          Ip + 56 * 2},
3237         /* layer 5 */
3238         {Kp,          Mp,          Sp,          Rp         },
3239         {Mp,          Ip,          Qp,          Sp         },
3240         {Np,          Lp,          Rp,          Tp         },
3241         {Jp,          Np,          Tp,          Qp + 56 * 1},
3242         {Pp,          Jp + 56 * 2, Qp + 56 * 3, Up         },
3243         {Lp,          Pp,          Up,          Rp         },
3244         {Op,          Kp,          Rp,          Vp         },
3245         {Ip + 56 * 2, Op,          Vp,          Qp + 56 * 2},
3246         /* layer 6 */
3247         {Rp,          Sp,          Aq,          Yp         },
3248         {Sp,          Qp,          Wp,          Aq         },
3249         {Tp,          Rp,          Yp,          Cq         },
3250         {Qp + 56 * 1, Tp,          Cq,          Wp + 56 * 1},
3251         {Up,          Qp + 56 * 3, Xp + 56 * 1, Dq         },
3252         {Rp,          Up,          Dq,          Zp         },
3253         {Vp,          Rp,          Zp,          Bq         },
3254         {Qp + 56 * 2, Vp,          Bq,          Xp         },
3255         /* layer 7 (the top is the periodic image of the bottom of layer 0) */
3256         {Yp,          Aq,          C + 56 * 4,  A + 56 * 4 },
3257         {Aq,          Wp,          B + 56 * 4,  C + 56 * 4 },
3258         {Cq,          Yp,          A + 56 * 4,  D + 56 * 4 },
3259         {Wp + 56 * 1, Cq,          D + 56 * 4,  B + 56 * 5 },
3260         {Dq,          Xp + 56 * 1, B + 56 * 5,  E + 56 * 4 },
3261         {Zp,          Dq,          E + 56 * 4,  A + 56 * 6 },
3262         {Bq,          Zp,          A + 56 * 6,  F + 56 * 4 },
3263         {Xp,          Bq,          F + 56 * 4,  B + 56 * 4 }
3264       };
3265       const PetscReal gamma                = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI;
3266       const PetscReal patternCoords[56][3] = {
3267         {1.,        0.,        0.  }, /* A  */
3268         {0.,        1.,        0.  }, /* B  */
3269         {gamma,     gamma,     0.  }, /* C  */
3270         {1 + gamma, 1 - gamma, 0.  }, /* D  */
3271         {2 - gamma, 2 - gamma, 0.  }, /* E  */
3272         {1 - gamma, 1 + gamma, 0.  }, /* F  */
3273 
3274         {.5,        0,         .25 }, /* G  */
3275         {1.5,       0.,        .25 }, /* H  */
3276         {.5,        1.,        .25 }, /* II */
3277         {1.5,       1.,        .25 }, /* J  */
3278         {.25,       .5,        .25 }, /* K  */
3279         {1.25,      .5,        .25 }, /* L  */
3280         {.75,       1.5,       .25 }, /* M  */
3281         {1.75,      1.5,       .25 }, /* N  */
3282 
3283         {0.,        0.,        .5  }, /* O  */
3284         {1.,        1.,        .5  }, /* P  */
3285         {gamma,     1 - gamma, .5  }, /* Q  */
3286         {1 + gamma, gamma,     .5  }, /* R  */
3287         {2 - gamma, 1 + gamma, .5  }, /* S  */
3288         {1 - gamma, 2 - gamma, .5  }, /* T  */
3289 
3290         {0.,        .5,        .75 }, /* U  */
3291         {0.,        1.5,       .75 }, /* V  */
3292         {1.,        .5,        .75 }, /* W  */
3293         {1.,        1.5,       .75 }, /* X  */
3294         {.5,        .75,       .75 }, /* Y  */
3295         {.5,        1.75,      .75 }, /* Z  */
3296         {1.5,       .25,       .75 }, /* Ap */
3297         {1.5,       1.25,      .75 }, /* Bp */
3298 
3299         {1.,        0.,        1.  }, /* Cp */
3300         {0.,        1.,        1.  }, /* Dp */
3301         {1 - gamma, 1 - gamma, 1.  }, /* Ep */
3302         {1 + gamma, 1 + gamma, 1.  }, /* Fp */
3303         {2 - gamma, gamma,     1.  }, /* Gp */
3304         {gamma,     2 - gamma, 1.  }, /* Hp */
3305 
3306         {.5,        0.,        1.25}, /* Ip */
3307         {1.5,       0.,        1.25}, /* Jp */
3308         {.5,        1.,        1.25}, /* Kp */
3309         {1.5,       1.,        1.25}, /* Lp */
3310         {.75,       .5,        1.25}, /* Mp */
3311         {1.75,      .5,        1.25}, /* Np */
3312         {.25,       1.5,       1.25}, /* Op */
3313         {1.25,      1.5,       1.25}, /* Pp */
3314 
3315         {0.,        0.,        1.5 }, /* Qp */
3316         {1.,        1.,        1.5 }, /* Rp */
3317         {1 - gamma, gamma,     1.5 }, /* Sp */
3318         {2 - gamma, 1 - gamma, 1.5 }, /* Tp */
3319         {1 + gamma, 2 - gamma, 1.5 }, /* Up */
3320         {gamma,     1 + gamma, 1.5 }, /* Vp */
3321 
3322         {0.,        .5,        1.75}, /* Wp */
3323         {0.,        1.5,       1.75}, /* Xp */
3324         {1.,        .5,        1.75}, /* Yp */
3325         {1.,        1.5,       1.75}, /* Zp */
3326         {.5,        .25,       1.75}, /* Aq */
3327         {.5,        1.25,      1.75}, /* Bq */
3328         {1.5,       .75,       1.75}, /* Cq */
3329         {1.5,       1.75,      1.75}, /* Dq */
3330       };
3331       PetscInt(*cells)[64][4] = NULL;
3332       PetscBool *seen;
3333       PetscInt  *vertToTrueVert;
3334       PetscInt   count;
3335 
3336       for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1;
3337       numBlocks = 1;
3338       for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i];
3339       numBlocksPlus = 1;
3340       for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i];
3341       numFaces = numBlocks * facesPerBlock;
3342       PetscCall(PetscMalloc1(numBlocks, &cells));
3343       PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen));
3344       for (PetscInt k = 0; k < extent[2]; k++) {
3345         for (PetscInt j = 0; j < extent[1]; j++) {
3346           for (PetscInt i = 0; i < extent[0]; i++) {
3347             for (PetscInt f = 0; f < facesPerBlock; f++) {
3348               for (PetscInt v = 0; v < 4; v++) {
3349                 PetscInt vertRaw     = pattern[f][v];
3350                 PetscInt blockidx    = vertRaw / 56;
3351                 PetscInt patternvert = vertRaw % 56;
3352                 PetscInt xplus       = (blockidx & 1);
3353                 PetscInt yplus       = (blockidx & 2) >> 1;
3354                 PetscInt zplus       = (blockidx & 4) >> 2;
3355                 PetscInt zcoord      = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus);
3356                 PetscInt ycoord      = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus);
3357                 PetscInt xcoord      = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus);
3358                 PetscInt vert        = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert;
3359 
3360                 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert;
3361                 seen[vert]                                       = PETSC_TRUE;
3362               }
3363             }
3364           }
3365         }
3366       }
3367       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++)
3368         if (seen[i]) numVertices++;
3369       count = 0;
3370       PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert));
3371       PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords));
3372       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1;
3373       for (PetscInt k = 0; k < extentPlus[2]; k++) {
3374         for (PetscInt j = 0; j < extentPlus[1]; j++) {
3375           for (PetscInt i = 0; i < extentPlus[0]; i++) {
3376             for (PetscInt v = 0; v < vertsPerBlock; v++) {
3377               PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v;
3378 
3379               if (seen[vIdx]) {
3380                 PetscInt thisVert;
3381 
3382                 vertToTrueVert[vIdx] = thisVert = count++;
3383 
3384                 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d];
3385                 vtxCoords[3 * thisVert + 0] += i * 2;
3386                 vtxCoords[3 * thisVert + 1] += j * 2;
3387                 vtxCoords[3 * thisVert + 2] += k * 2;
3388               }
3389             }
3390           }
3391         }
3392       }
3393       for (PetscInt i = 0; i < numBlocks; i++) {
3394         for (PetscInt f = 0; f < facesPerBlock; f++) {
3395           for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]];
3396         }
3397       }
3398       PetscCall(PetscFree(vertToTrueVert));
3399       PetscCall(PetscFree(seen));
3400       cells_flat = cells[0][0];
3401       numEdges   = 0;
3402       for (PetscInt i = 0; i < numFaces; i++) {
3403         for (PetscInt e = 0; e < 4; e++) {
3404           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3405           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
3406 
3407           for (PetscInt d = 0; d < 3; d++) {
3408             if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) {
3409               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++;
3410               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++;
3411             }
3412           }
3413         }
3414       }
3415       PetscCall(PetscMalloc1(numEdges, &edges));
3416       PetscCall(PetscMalloc1(numEdges, &edgeSets));
3417       for (PetscInt edge = 0, i = 0; i < numFaces; i++) {
3418         for (PetscInt e = 0; e < 4; e++) {
3419           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
3420           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
3421 
3422           for (PetscInt d = 0; d < 3; d++) {
3423             if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) {
3424               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) {
3425                 edges[edge][0]   = ev[0];
3426                 edges[edge][1]   = ev[1];
3427                 edgeSets[edge++] = 2 * d;
3428               }
3429               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) {
3430                 edges[edge][0]   = ev[0];
3431                 edges[edge][1]   = ev[1];
3432                 edgeSets[edge++] = 2 * d + 1;
3433               }
3434             }
3435           }
3436         }
3437       }
3438     }
3439     evalFunc   = TPSEvaluate_Gyroid;
3440     normalFunc = TPSExtrudeNormalFunc_Gyroid;
3441     break;
3442   }
3443 
3444   PetscCall(DMSetDimension(dm, topoDim));
3445   if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat));
3446   else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL));
3447   PetscCall(PetscFree(cells_flat));
3448   {
3449     DM idm;
3450     PetscCall(DMPlexInterpolate(dm, &idm));
3451     PetscCall(DMPlexReplace_Internal(dm, &idm));
3452   }
3453   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords));
3454   else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL));
3455   PetscCall(PetscFree(vtxCoords));
3456 
3457   PetscCall(DMCreateLabel(dm, "Face Sets"));
3458   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3459   for (PetscInt e = 0; e < numEdges; e++) {
3460     PetscInt        njoin;
3461     const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]};
3462     PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join));
3463     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]);
3464     PetscCall(DMLabelSetValue(label, join[0], edgeSets[e]));
3465     PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join));
3466   }
3467   PetscCall(PetscFree(edges));
3468   PetscCall(PetscFree(edgeSets));
3469   if (tps_distribute) {
3470     DM               pdm = NULL;
3471     PetscPartitioner part;
3472 
3473     PetscCall(DMPlexGetPartitioner(dm, &part));
3474     PetscCall(PetscPartitionerSetFromOptions(part));
3475     PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm));
3476     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
3477     // Do not auto-distribute again
3478     PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
3479   }
3480 
3481   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
3482   for (PetscInt refine = 0; refine < refinements; refine++) {
3483     PetscInt     m;
3484     DM           dmf;
3485     Vec          X;
3486     PetscScalar *x;
3487     PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf));
3488     PetscCall(DMPlexReplace_Internal(dm, &dmf));
3489 
3490     PetscCall(DMGetCoordinatesLocal(dm, &X));
3491     PetscCall(VecGetLocalSize(X, &m));
3492     PetscCall(VecGetArray(X, &x));
3493     for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i]));
3494     PetscCall(VecRestoreArray(X, &x));
3495   }
3496 
3497   // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices.
3498   PetscCall(DMGetLabel(dm, "Face Sets", &label));
3499   PetscCall(DMPlexLabelComplete(dm, label));
3500 
3501   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
3502 
3503   if (thickness > 0) {
3504     DM              edm, cdm, ecdm;
3505     DMPlexTransform tr;
3506     const char     *prefix;
3507     PetscOptions    options;
3508     // Code from DMPlexExtrude
3509     PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
3510     PetscCall(DMPlexTransformSetDM(tr, dm));
3511     PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDE));
3512     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
3513     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
3514     PetscCall(PetscObjectGetOptions((PetscObject)dm, &options));
3515     PetscCall(PetscObjectSetOptions((PetscObject)tr, options));
3516     PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers));
3517     PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness));
3518     PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE));
3519     PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE));
3520     PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc));
3521     PetscCall(DMPlexTransformSetFromOptions(tr));
3522     PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
3523     PetscCall(DMPlexTransformSetUp(tr));
3524     PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view"));
3525     PetscCall(DMPlexTransformApply(tr, dm, &edm));
3526     PetscCall(DMCopyDisc(dm, edm));
3527     PetscCall(DMGetCoordinateDM(dm, &cdm));
3528     PetscCall(DMGetCoordinateDM(edm, &ecdm));
3529     PetscCall(DMCopyDisc(cdm, ecdm));
3530     PetscCall(DMPlexTransformCreateDiscLabels(tr, edm));
3531     PetscCall(DMPlexTransformDestroy(&tr));
3532     if (edm) {
3533       ((DM_Plex *)edm->data)->printFEM    = ((DM_Plex *)dm->data)->printFEM;
3534       ((DM_Plex *)edm->data)->printL2     = ((DM_Plex *)dm->data)->printL2;
3535       ((DM_Plex *)edm->data)->printLocate = ((DM_Plex *)dm->data)->printLocate;
3536     }
3537     PetscCall(DMPlexReplace_Internal(dm, &edm));
3538   }
3539   PetscFunctionReturn(PETSC_SUCCESS);
3540 }
3541 
3542 /*@
3543   DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface
3544 
3545   Collective
3546 
3547   Input Parameters:
3548 + comm           - The communicator for the `DM` object
3549 . tpstype        - Type of triply-periodic surface
3550 . extent         - Array of length 3 containing number of periods in each direction
3551 . periodic       - array of length 3 with periodicity, or `NULL` for non-periodic
3552 . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable)
3553 . refinements    - Number of factor-of-2 refinements of 2D manifold mesh
3554 . layers         - Number of cell layers extruded in normal direction
3555 - thickness      - Thickness in normal direction
3556 
3557   Output Parameter:
3558 . dm - The `DM` object
3559 
3560   Level: beginner
3561 
3562   Notes:
3563   This meshes the surface of the Schwarz P or Gyroid surfaces.  Schwarz P is the simplest member of the triply-periodic minimal surfaces.
3564   <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries.
3565   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.
3566   Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested.
3567   On each refinement, all vertices are projected to their nearest point on the surface.
3568   This projection could readily be extended to related surfaces.
3569 
3570   See {cite}`maskery2018insights`
3571 
3572   The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$.
3573   When the mesh is refined, "Face Sets" contain the new vertices (created during refinement).
3574   Use `DMPlexLabelComplete()` to propagate to coarse-level vertices.
3575 
3576   Developer Notes:
3577   The Gyroid mesh does not currently mark boundary sets.
3578 
3579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()`
3580 @*/
3581 PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm)
3582 {
3583   PetscFunctionBegin;
3584   PetscCall(DMCreate(comm, dm));
3585   PetscCall(DMSetType(*dm, DMPLEX));
3586   PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness));
3587   PetscFunctionReturn(PETSC_SUCCESS);
3588 }
3589 
3590 /*@
3591   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
3592 
3593   Collective
3594 
3595   Input Parameters:
3596 + comm    - The communicator for the `DM` object
3597 . dim     - The dimension
3598 . simplex - Use simplices, or tensor product cells
3599 - R       - The radius
3600 
3601   Output Parameter:
3602 . dm - The `DM` object
3603 
3604   Level: beginner
3605 
3606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3607 @*/
3608 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
3609 {
3610   PetscFunctionBegin;
3611   PetscAssertPointer(dm, 5);
3612   PetscCall(DMCreate(comm, dm));
3613   PetscCall(DMSetType(*dm, DMPLEX));
3614   PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R));
3615   PetscFunctionReturn(PETSC_SUCCESS);
3616 }
3617 
3618 static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R)
3619 {
3620   DM          sdm, vol;
3621   DMLabel     bdlabel;
3622   const char *prefix;
3623 
3624   PetscFunctionBegin;
3625   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
3626   PetscCall(DMSetType(sdm, DMPLEX));
3627   PetscCall(DMGetOptionsPrefix(dm, &prefix));
3628   PetscCall(DMSetOptionsPrefix(sdm, prefix));
3629   PetscCall(DMAppendOptionsPrefix(sdm, "bd_"));
3630   PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE));
3631   PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R));
3632   PetscCall(DMSetFromOptions(sdm));
3633   PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view"));
3634   PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol));
3635   PetscCall(DMDestroy(&sdm));
3636   PetscCall(DMPlexReplace_Internal(dm, &vol));
3637   PetscCall(DMCreateLabel(dm, "marker"));
3638   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
3639   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
3640   PetscCall(DMPlexLabelComplete(dm, bdlabel));
3641   PetscFunctionReturn(PETSC_SUCCESS);
3642 }
3643 
3644 /*@
3645   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.
3646 
3647   Collective
3648 
3649   Input Parameters:
3650 + comm - The communicator for the `DM` object
3651 . dim  - The dimension
3652 - R    - The radius
3653 
3654   Output Parameter:
3655 . dm - The `DM` object
3656 
3657   Options Database Key:
3658 . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry
3659 
3660   Level: beginner
3661 
3662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
3663 @*/
3664 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
3665 {
3666   PetscFunctionBegin;
3667   PetscCall(DMCreate(comm, dm));
3668   PetscCall(DMSetType(*dm, DMPLEX));
3669   PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R));
3670   PetscFunctionReturn(PETSC_SUCCESS);
3671 }
3672 
3673 static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct)
3674 {
3675   PetscFunctionBegin;
3676   switch (ct) {
3677   case DM_POLYTOPE_POINT: {
3678     PetscInt    numPoints[1]        = {1};
3679     PetscInt    coneSize[1]         = {0};
3680     PetscInt    cones[1]            = {0};
3681     PetscInt    coneOrientations[1] = {0};
3682     PetscScalar vertexCoords[1]     = {0.0};
3683 
3684     PetscCall(DMSetDimension(rdm, 0));
3685     PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3686   } break;
3687   case DM_POLYTOPE_SEGMENT: {
3688     PetscInt    numPoints[2]        = {2, 1};
3689     PetscInt    coneSize[3]         = {2, 0, 0};
3690     PetscInt    cones[2]            = {1, 2};
3691     PetscInt    coneOrientations[2] = {0, 0};
3692     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
3693 
3694     PetscCall(DMSetDimension(rdm, 1));
3695     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3696   } break;
3697   case DM_POLYTOPE_POINT_PRISM_TENSOR: {
3698     PetscInt    numPoints[2]        = {2, 1};
3699     PetscInt    coneSize[3]         = {2, 0, 0};
3700     PetscInt    cones[2]            = {1, 2};
3701     PetscInt    coneOrientations[2] = {0, 0};
3702     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
3703 
3704     PetscCall(DMSetDimension(rdm, 1));
3705     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3706   } break;
3707   case DM_POLYTOPE_TRIANGLE: {
3708     PetscInt    numPoints[2]        = {3, 1};
3709     PetscInt    coneSize[4]         = {3, 0, 0, 0};
3710     PetscInt    cones[3]            = {1, 2, 3};
3711     PetscInt    coneOrientations[3] = {0, 0, 0};
3712     PetscScalar vertexCoords[6]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0};
3713 
3714     PetscCall(DMSetDimension(rdm, 2));
3715     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3716   } break;
3717   case DM_POLYTOPE_QUADRILATERAL: {
3718     PetscInt    numPoints[2]        = {4, 1};
3719     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3720     PetscInt    cones[4]            = {1, 2, 3, 4};
3721     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3722     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0};
3723 
3724     PetscCall(DMSetDimension(rdm, 2));
3725     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3726   } break;
3727   case DM_POLYTOPE_SEG_PRISM_TENSOR: {
3728     PetscInt    numPoints[2]        = {4, 1};
3729     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3730     PetscInt    cones[4]            = {1, 2, 3, 4};
3731     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3732     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
3733 
3734     PetscCall(DMSetDimension(rdm, 2));
3735     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3736   } break;
3737   case DM_POLYTOPE_TETRAHEDRON: {
3738     PetscInt    numPoints[2]        = {4, 1};
3739     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3740     PetscInt    cones[4]            = {1, 2, 3, 4};
3741     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3742     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};
3743 
3744     PetscCall(DMSetDimension(rdm, 3));
3745     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3746   } break;
3747   case DM_POLYTOPE_HEXAHEDRON: {
3748     PetscInt    numPoints[2]        = {8, 1};
3749     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3750     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3751     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3752     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};
3753 
3754     PetscCall(DMSetDimension(rdm, 3));
3755     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3756   } break;
3757   case DM_POLYTOPE_TRI_PRISM: {
3758     PetscInt    numPoints[2]        = {6, 1};
3759     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3760     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3761     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3762     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};
3763 
3764     PetscCall(DMSetDimension(rdm, 3));
3765     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3766   } break;
3767   case DM_POLYTOPE_TRI_PRISM_TENSOR: {
3768     PetscInt    numPoints[2]        = {6, 1};
3769     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3770     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3771     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3772     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};
3773 
3774     PetscCall(DMSetDimension(rdm, 3));
3775     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3776   } break;
3777   case DM_POLYTOPE_QUAD_PRISM_TENSOR: {
3778     PetscInt    numPoints[2]        = {8, 1};
3779     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3780     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3781     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3782     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};
3783 
3784     PetscCall(DMSetDimension(rdm, 3));
3785     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3786   } break;
3787   case DM_POLYTOPE_PYRAMID: {
3788     PetscInt    numPoints[2]        = {5, 1};
3789     PetscInt    coneSize[6]         = {5, 0, 0, 0, 0, 0};
3790     PetscInt    cones[5]            = {1, 2, 3, 4, 5};
3791     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3792     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};
3793 
3794     PetscCall(DMSetDimension(rdm, 3));
3795     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
3796   } break;
3797   default:
3798     SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
3799   }
3800   {
3801     PetscInt Nv, v;
3802 
3803     /* Must create the celltype label here so that we do not automatically try to compute the types */
3804     PetscCall(DMCreateLabel(rdm, "celltype"));
3805     PetscCall(DMPlexSetCellType(rdm, 0, ct));
3806     PetscCall(DMPlexGetChart(rdm, NULL, &Nv));
3807     for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT));
3808   }
3809   PetscCall(DMPlexInterpolateInPlace_Internal(rdm));
3810   PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct]));
3811   PetscFunctionReturn(PETSC_SUCCESS);
3812 }
3813 
3814 /*@
3815   DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell
3816 
3817   Collective
3818 
3819   Input Parameters:
3820 + comm - The communicator
3821 - ct   - The cell type of the reference cell
3822 
3823   Output Parameter:
3824 . refdm - The reference cell
3825 
3826   Level: intermediate
3827 
3828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`
3829 @*/
3830 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
3831 {
3832   PetscFunctionBegin;
3833   PetscCall(DMCreate(comm, refdm));
3834   PetscCall(DMSetType(*refdm, DMPLEX));
3835   PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct));
3836   PetscFunctionReturn(PETSC_SUCCESS);
3837 }
3838 
3839 static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[])
3840 {
3841   DM        plex;
3842   DMLabel   label;
3843   PetscBool hasLabel;
3844 
3845   PetscFunctionBegin;
3846   PetscCall(DMHasLabel(dm, name, &hasLabel));
3847   if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS);
3848   PetscCall(DMCreateLabel(dm, name));
3849   PetscCall(DMGetLabel(dm, name, &label));
3850   PetscCall(DMConvert(dm, DMPLEX, &plex));
3851   PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label));
3852   PetscCall(DMPlexLabelComplete(plex, label));
3853   PetscCall(DMDestroy(&plex));
3854   PetscFunctionReturn(PETSC_SUCCESS);
3855 }
3856 
3857 /*
3858   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.
3859 
3860     (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0]))
3861 */
3862 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[])
3863 {
3864   const PetscReal low = PetscRealPart(constants[0]);
3865   const PetscReal upp = PetscRealPart(constants[1]);
3866   const PetscReal r   = PetscRealPart(u[1]);
3867   const PetscReal th  = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low);
3868 
3869   f0[0] = r * PetscCosReal(th);
3870   f0[1] = r * PetscSinReal(th);
3871 }
3872 
3873 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);
3874 
3875 const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL};
3876 
3877 static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems *PetscOptionsObject, PetscBool *useCoordSpace, DM dm)
3878 {
3879   DMPlexShape    shape   = DM_SHAPE_BOX;
3880   DMPolytopeType cell    = DM_POLYTOPE_TRIANGLE;
3881   PetscInt       dim     = 2;
3882   PetscBool      simplex = PETSC_TRUE, interpolate = PETSC_TRUE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE;
3883   PetscBool      flg, flg2, fflg, strflg, bdfflg, nameflg;
3884   MPI_Comm       comm;
3885   char           filename[PETSC_MAX_PATH_LEN]   = "<unspecified>";
3886   char           bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>";
3887   char           plexname[PETSC_MAX_PATH_LEN]   = "";
3888   const char    *option;
3889 
3890   PetscFunctionBegin;
3891   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
3892   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3893   /* TODO Turn this into a registration interface */
3894   PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg));
3895   PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg));
3896   PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg));
3897   PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg));
3898   PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL));
3899   PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL));
3900   PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg));
3901   PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0));
3902   PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg));
3903   PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg));
3904   PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg));
3905   PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2));
3906   if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure));
3907 
3908   switch (cell) {
3909   case DM_POLYTOPE_POINT:
3910   case DM_POLYTOPE_SEGMENT:
3911   case DM_POLYTOPE_POINT_PRISM_TENSOR:
3912   case DM_POLYTOPE_TRIANGLE:
3913   case DM_POLYTOPE_QUADRILATERAL:
3914   case DM_POLYTOPE_TETRAHEDRON:
3915   case DM_POLYTOPE_HEXAHEDRON:
3916     *useCoordSpace = PETSC_TRUE;
3917     break;
3918   default:
3919     *useCoordSpace = PETSC_FALSE;
3920     break;
3921   }
3922 
3923   if (fflg) {
3924     DM dmnew;
3925 
3926     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, plexname, interpolate, &dmnew));
3927     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3928     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3929   } else if (refDomain) {
3930     PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell));
3931   } else if (bdfflg) {
3932     DM bdm, dmnew;
3933 
3934     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, plexname, interpolate, &bdm));
3935     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_"));
3936     PetscCall(DMSetFromOptions(bdm));
3937     PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew));
3938     PetscCall(DMDestroy(&bdm));
3939     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3940     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3941   } else if (strflg) {
3942     DM            dmnew;
3943     PetscViewer   viewer;
3944     const char   *contents;
3945     char         *strname;
3946     char          tmpdir[PETSC_MAX_PATH_LEN];
3947     char          tmpfilename[PETSC_MAX_PATH_LEN];
3948     char          name[PETSC_MAX_PATH_LEN];
3949     PetscObjectId id;
3950     MPI_Comm      comm;
3951     PetscMPIInt   rank;
3952 
3953     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3954     PetscCallMPI(MPI_Comm_rank(comm, &rank));
3955     PetscCall(PetscStrchr(filename, ':', &strname));
3956     PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename);
3957     strname[0] = '\0';
3958     ++strname;
3959     PetscCall(PetscDLSym(NULL, strname, (void **)&contents));
3960     PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname);
3961     PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN));
3962     PetscCall(PetscObjectGetId((PetscObject)dm, &id));
3963     PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh_%d.%s", tmpdir, (int)id, filename));
3964     PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer));
3965     PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents));
3966     PetscCall(PetscViewerDestroy(&viewer));
3967     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew));
3968     if (!rank && !unlink(tmpfilename)) PetscCall(PetscInfo(dm, "Could not delete file: %s due to \"%s\"\n", tmpfilename, strerror(errno)));
3969     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname));
3970     PetscCall(PetscObjectSetName((PetscObject)dm, name));
3971     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
3972     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
3973   } else {
3974     PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape]));
3975     switch (shape) {
3976     case DM_SHAPE_BOX:
3977     case DM_SHAPE_ZBOX:
3978     case DM_SHAPE_ANNULUS: {
3979       PetscInt       faces[3]  = {0, 0, 0};
3980       PetscReal      lower[3]  = {0, 0, 0};
3981       PetscReal      upper[3]  = {1, 1, 1};
3982       DMBoundaryType bdt[3]    = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
3983       PetscBool      isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE;
3984       PetscInt       i, n;
3985 
3986       n = dim;
3987       for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim);
3988       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
3989       n = 3;
3990       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
3991       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3992       n = 3;
3993       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
3994       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3995       n = 3;
3996       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
3997       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
3998 
3999       PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented");
4000       if (isAnnular)
4001         for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC;
4002 
4003       switch (cell) {
4004       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4005         PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt));
4006         if (!interpolate) {
4007           DM udm;
4008 
4009           PetscCall(DMPlexUninterpolate(dm, &udm));
4010           PetscCall(DMPlexReplace_Internal(dm, &udm));
4011         }
4012         break;
4013       default:
4014         PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate));
4015         break;
4016       }
4017       if (isAnnular) {
4018         DM          cdm;
4019         PetscDS     cds;
4020         PetscScalar bounds[2] = {lower[0], upper[0]};
4021 
4022         // Fix coordinates for annular region
4023         PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
4024         PetscCall(DMSetCellCoordinatesLocal(dm, NULL));
4025         PetscCall(DMSetCellCoordinates(dm, NULL));
4026         PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_TRUE, NULL));
4027         PetscCall(DMGetCoordinateDM(dm, &cdm));
4028         PetscCall(DMGetDS(cdm, &cds));
4029         PetscCall(PetscDSSetConstants(cds, 2, bounds));
4030         PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus));
4031       }
4032     } break;
4033     case DM_SHAPE_BOX_SURFACE: {
4034       PetscInt  faces[3] = {0, 0, 0};
4035       PetscReal lower[3] = {0, 0, 0};
4036       PetscReal upper[3] = {1, 1, 1};
4037       PetscInt  i, n;
4038 
4039       n = dim + 1;
4040       for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1));
4041       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
4042       n = 3;
4043       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4044       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);
4045       n = 3;
4046       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4047       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);
4048       PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate));
4049     } break;
4050     case DM_SHAPE_SPHERE: {
4051       PetscReal R = 1.0;
4052 
4053       PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg));
4054       PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R));
4055     } break;
4056     case DM_SHAPE_BALL: {
4057       PetscReal R = 1.0;
4058 
4059       PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg));
4060       PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R));
4061     } break;
4062     case DM_SHAPE_CYLINDER: {
4063       DMBoundaryType bdt = DM_BOUNDARY_NONE;
4064       PetscInt       Nw  = 6;
4065 
4066       PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL));
4067       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL));
4068       switch (cell) {
4069       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4070         PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate));
4071         break;
4072       default:
4073         PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt));
4074         break;
4075       }
4076     } break;
4077     case DM_SHAPE_SCHWARZ_P: // fallthrough
4078     case DM_SHAPE_GYROID: {
4079       PetscInt       extent[3] = {1, 1, 1}, refine = 0, layers = 0, three;
4080       PetscReal      thickness   = 0.;
4081       DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4082       DMPlexTPSType  tps_type    = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID;
4083       PetscBool      tps_distribute;
4084       PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL));
4085       PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL));
4086       PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL));
4087       PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL));
4088       PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL));
4089       PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute));
4090       PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL));
4091       PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness));
4092     } break;
4093     case DM_SHAPE_DOUBLET: {
4094       DM        dmnew;
4095       PetscReal rl = 0.0;
4096 
4097       PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL));
4098       PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew));
4099       PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4100       PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4101     } break;
4102     case DM_SHAPE_HYPERCUBIC: {
4103       PetscInt       *edges;
4104       PetscReal      *lower, *upper;
4105       DMBoundaryType *bdt;
4106       PetscInt        n, d;
4107 
4108       *useCoordSpace = PETSC_FALSE;
4109       PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt));
4110       for (d = 0; d < dim; ++d) {
4111         edges[d] = 1;
4112         lower[d] = 0.;
4113         upper[d] = 1.;
4114         bdt[d]   = DM_BOUNDARY_PERIODIC;
4115       }
4116       n = dim;
4117       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg));
4118       n = dim;
4119       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4120       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4121       n = dim;
4122       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4123       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4124       n = dim;
4125       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4126       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4127       PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, bdt));
4128       PetscCall(PetscFree4(edges, lower, upper, bdt));
4129     } break;
4130     default:
4131       SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]);
4132     }
4133   }
4134   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4135   if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname));
4136   // Allow label creation
4137   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg));
4138   if (flg) {
4139     DMLabel     label;
4140     PetscInt    points[1024], n = 1024;
4141     char        fulloption[PETSC_MAX_PATH_LEN];
4142     const char *name = &option[14];
4143 
4144     PetscCall(DMCreateLabel(dm, name));
4145     PetscCall(DMGetLabel(dm, name, &label));
4146     fulloption[0] = '-';
4147     fulloption[1] = 0;
4148     PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN));
4149     PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL));
4150     for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1));
4151   }
4152   // Allow cohesive label creation
4153   //   Faces are input, completed, and all points are marked with their depth
4154   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg));
4155   if (flg) {
4156     DMLabel  label;
4157     PetscInt points[1024], n, pStart, pEnd, Nl = 1;
4158     char     fulloption[PETSC_MAX_PATH_LEN];
4159     char     name[PETSC_MAX_PATH_LEN];
4160     size_t   len;
4161 
4162     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4163     PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN));
4164     PetscCall(PetscStrlen(name, &len));
4165     if (name[len - 1] == '0') Nl = 10;
4166     for (PetscInt l = 0; l < Nl; ++l) {
4167       if (l > 0) name[len - 1] = '0' + l;
4168       fulloption[0] = 0;
4169       PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32));
4170       PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32));
4171       n = 1024;
4172       PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg));
4173       if (!flg) break;
4174       PetscCall(DMCreateLabel(dm, name));
4175       PetscCall(DMGetLabel(dm, name, &label));
4176       if (pStart >= pEnd) n = 0;
4177       for (PetscInt p = 0; p < n; ++p) {
4178         const PetscInt point   = points[p];
4179         PetscInt      *closure = NULL;
4180         PetscInt       clSize, pdepth;
4181 
4182         PetscCall(DMPlexGetPointDepth(dm, point, &pdepth));
4183         PetscCall(DMLabelSetValue(label, point, pdepth));
4184         PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4185         for (PetscInt cl = 0; cl < clSize * 2; cl += 2) {
4186           PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth));
4187           PetscCall(DMLabelSetValue(label, closure[cl], pdepth));
4188         }
4189         PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
4190       }
4191       PetscCall(DMPlexOrientLabel(dm, label));
4192       PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL));
4193     }
4194   }
4195   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
4196   PetscFunctionReturn(PETSC_SUCCESS);
4197 }
4198 
4199 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4200 {
4201   DM_Plex  *mesh = (DM_Plex *)dm->data;
4202   PetscBool flg, flg2;
4203   char      bdLabel[PETSC_MAX_PATH_LEN];
4204   char      method[PETSC_MAX_PATH_LEN];
4205 
4206   PetscFunctionBegin;
4207   /* Handle viewing */
4208   PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL));
4209   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0));
4210   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0));
4211   PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL));
4212   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0));
4213   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0));
4214   PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg));
4215   if (flg) PetscCall(PetscLogDefaultBegin());
4216   /* Labeling */
4217   PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", bdLabel, bdLabel, sizeof(bdLabel), &flg));
4218   if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel));
4219   /* Point Location */
4220   PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL));
4221   /* Partitioning and distribution */
4222   PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL));
4223   /* Reordering */
4224   PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg));
4225   if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE));
4226   PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", method, method, PETSC_MAX_PATH_LEN, &flg));
4227   if (flg) PetscCall(DMReorderSectionSetType(dm, method));
4228   /* Generation and remeshing */
4229   PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL));
4230   /* Projection behavior */
4231   PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0));
4232   PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL));
4233   /* Checking structure */
4234   {
4235     PetscBool all = PETSC_FALSE;
4236 
4237     PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL));
4238     if (all) {
4239       PetscCall(DMPlexCheck(dm));
4240     } else {
4241       PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2));
4242       if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm));
4243       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));
4244       if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0));
4245       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));
4246       if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0));
4247       PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2));
4248       if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm));
4249       PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2));
4250       if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
4251       PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2));
4252       if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm));
4253     }
4254     PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2));
4255     if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE));
4256   }
4257   {
4258     PetscReal scale = 1.0;
4259 
4260     PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg));
4261     if (flg) {
4262       Vec coordinates, coordinatesLocal;
4263 
4264       PetscCall(DMGetCoordinates(dm, &coordinates));
4265       PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
4266       PetscCall(VecScale(coordinates, scale));
4267       PetscCall(VecScale(coordinatesLocal, scale));
4268     }
4269   }
4270   PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner));
4271   PetscFunctionReturn(PETSC_SUCCESS);
4272 }
4273 
4274 PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems *PetscOptionsObject, PetscInt *overlap)
4275 {
4276   PetscInt  numOvLabels = 16, numOvExLabels = 16;
4277   char     *ovLabelNames[16], *ovExLabelNames[16];
4278   PetscInt  numOvValues = 16, numOvExValues = 16, l;
4279   PetscBool flg;
4280 
4281   PetscFunctionBegin;
4282   PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0));
4283   PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg));
4284   if (!flg) numOvLabels = 0;
4285   if (numOvLabels) {
4286     ((DM_Plex *)dm->data)->numOvLabels = numOvLabels;
4287     for (l = 0; l < numOvLabels; ++l) {
4288       PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l]));
4289       PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]);
4290       PetscCall(PetscFree(ovLabelNames[l]));
4291     }
4292     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg));
4293     if (!flg) numOvValues = 0;
4294     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);
4295 
4296     PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg));
4297     if (!flg) numOvExLabels = 0;
4298     ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels;
4299     for (l = 0; l < numOvExLabels; ++l) {
4300       PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l]));
4301       PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]);
4302       PetscCall(PetscFree(ovExLabelNames[l]));
4303     }
4304     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg));
4305     if (!flg) numOvExValues = 0;
4306     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);
4307   }
4308   PetscFunctionReturn(PETSC_SUCCESS);
4309 }
4310 
4311 static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems *PetscOptionsObject)
4312 {
4313   PetscFunctionList    ordlist;
4314   char                 oname[256];
4315   char                 sublabelname[PETSC_MAX_PATH_LEN] = "";
4316   DMReorderDefaultFlag reorder;
4317   PetscReal            volume    = -1.0;
4318   PetscInt             prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim;
4319   PetscBool uniformOrig = PETSC_FALSE, created = PETSC_FALSE, uniform = PETSC_TRUE, distribute, saveSF = PETSC_FALSE, interpolate = PETSC_TRUE, coordSpace = PETSC_TRUE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, ignoreModel = PETSC_FALSE, flg;
4320 
4321   PetscFunctionBegin;
4322   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options");
4323   if (dm->cloneOpts) goto non_refine;
4324   /* Handle automatic creation */
4325   PetscCall(DMGetDimension(dm, &dim));
4326   if (dim < 0) {
4327     PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm));
4328     created = PETSC_TRUE;
4329   }
4330   PetscCall(DMGetDimension(dm, &dim));
4331   /* Handle interpolation before distribution */
4332   PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg));
4333   if (flg) {
4334     DMPlexInterpolatedFlag interpolated;
4335 
4336     PetscCall(DMPlexIsInterpolated(dm, &interpolated));
4337     if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) {
4338       DM udm;
4339 
4340       PetscCall(DMPlexUninterpolate(dm, &udm));
4341       PetscCall(DMPlexReplace_Internal(dm, &udm));
4342     } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) {
4343       DM idm;
4344 
4345       PetscCall(DMPlexInterpolate(dm, &idm));
4346       PetscCall(DMPlexReplace_Internal(dm, &idm));
4347     }
4348   }
4349   // Handle submesh selection before distribution
4350   PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg));
4351   if (flg) {
4352     DM              subdm;
4353     DMLabel         label;
4354     IS              valueIS, pointIS;
4355     const PetscInt *values, *points;
4356     PetscBool       markedFaces = PETSC_FALSE;
4357     PetscInt        Nv, value, Np;
4358 
4359     PetscCall(DMGetLabel(dm, sublabelname, &label));
4360     PetscCall(DMLabelGetNumValues(label, &Nv));
4361     PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv);
4362     PetscCall(DMLabelGetValueIS(label, &valueIS));
4363     PetscCall(ISGetIndices(valueIS, &values));
4364     value = values[0];
4365     PetscCall(ISRestoreIndices(valueIS, &values));
4366     PetscCall(ISDestroy(&valueIS));
4367     PetscCall(DMLabelGetStratumSize(label, value, &Np));
4368     PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
4369     PetscCall(ISGetIndices(pointIS, &points));
4370     for (PetscInt p = 0; p < Np; ++p) {
4371       PetscInt pdepth;
4372 
4373       PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth));
4374       if (pdepth) {
4375         markedFaces = PETSC_TRUE;
4376         break;
4377       }
4378     }
4379     PetscCall(ISRestoreIndices(pointIS, &points));
4380     PetscCall(ISDestroy(&pointIS));
4381     PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm));
4382     PetscCall(DMPlexReplace_Internal(dm, &subdm));
4383     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4384   }
4385   /* Handle DMPlex refinement before distribution */
4386   PetscCall(PetscOptionsBool("-dm_refine_ignore_model", "Flag to ignore the geometry model when refining", "DMCreate", ignoreModel, &ignoreModel, &flg));
4387   if (flg) ((DM_Plex *)dm->data)->ignoreModel = ignoreModel;
4388   PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig));
4389   PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0));
4390   PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4391   PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg));
4392   if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform));
4393   PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg));
4394   if (flg) {
4395     PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE));
4396     PetscCall(DMPlexSetRefinementLimit(dm, volume));
4397     prerefine = PetscMax(prerefine, 1);
4398   }
4399   if (prerefine) PetscCall(DMLocalizeCoordinates(dm));
4400   for (r = 0; r < prerefine; ++r) {
4401     DM             rdm;
4402     PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;
4403 
4404     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4405     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4406     PetscCall(DMPlexReplace_Internal(dm, &rdm));
4407     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4408     if (coordFunc && remap) {
4409       PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4410       ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4411     }
4412   }
4413   PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig));
4414   /* Handle DMPlex extrusion before distribution */
4415   PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0));
4416   if (extLayers) {
4417     DM edm;
4418 
4419     PetscCall(DMExtrude(dm, extLayers, &edm));
4420     PetscCall(DMPlexReplace_Internal(dm, &edm));
4421     ((DM_Plex *)dm->data)->coordFunc = NULL;
4422     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4423     extLayers = 0;
4424     PetscCall(DMGetDimension(dm, &dim));
4425   }
4426   /* Handle DMPlex reordering before distribution */
4427   PetscCall(DMPlexReorderGetDefault(dm, &reorder));
4428   PetscCall(MatGetOrderingList(&ordlist));
4429   PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname)));
4430   PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg));
4431   if (reorder == DM_REORDER_DEFAULT_TRUE || flg) {
4432     DM pdm;
4433     IS perm;
4434 
4435     PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm));
4436     PetscCall(DMPlexPermute(dm, perm, &pdm));
4437     PetscCall(ISDestroy(&perm));
4438     PetscCall(DMPlexReplace_Internal(dm, &pdm));
4439     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4440   }
4441   /* Handle DMPlex distribution */
4442   PetscCall(DMPlexDistributeGetDefault(dm, &distribute));
4443   PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL));
4444   PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL));
4445   PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
4446   if (distribute) {
4447     DM               pdm = NULL;
4448     PetscPartitioner part;
4449     PetscSF          sfMigration;
4450 
4451     PetscCall(DMPlexGetPartitioner(dm, &part));
4452     PetscCall(PetscPartitionerSetFromOptions(part));
4453     PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm));
4454     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
4455     if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration));
4456     PetscCall(PetscSFDestroy(&sfMigration));
4457   }
4458   /* Must check CEED options before creating function space for coordinates */
4459   {
4460     PetscBool useCeed = PETSC_FALSE, flg;
4461 
4462     PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg));
4463     if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed));
4464   }
4465   /* Create coordinate space */
4466   if (created) {
4467     DM_Plex  *mesh   = (DM_Plex *)dm->data;
4468     PetscInt  degree = 1, deg;
4469     PetscInt  height = 0;
4470     DM        cdm;
4471     PetscBool flg, localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE;
4472 
4473     PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, &flg));
4474     PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, &degree, NULL));
4475     PetscCall(DMGetCoordinateDegree_Internal(dm, &deg));
4476     if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_TRUE, mesh->coordFunc));
4477     PetscCall(DMGetCoordinateDM(dm, &cdm));
4478     if (flg && !coordSpace) {
4479       PetscDS      cds;
4480       PetscObject  obj;
4481       PetscClassId id;
4482 
4483       PetscCall(DMGetDS(cdm, &cds));
4484       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4485       PetscCall(PetscObjectGetClassId(obj, &id));
4486       if (id == PETSCFE_CLASSID) {
4487         PetscContainer dummy;
4488 
4489         PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy));
4490         PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates"));
4491         PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy));
4492         PetscCall(PetscContainerDestroy(&dummy));
4493         PetscCall(DMClearDS(cdm));
4494       }
4495       mesh->coordFunc = NULL;
4496     }
4497     PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL));
4498     PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg));
4499     if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize));
4500     PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg));
4501     if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height));
4502     if (localize) PetscCall(DMLocalizeCoordinates(dm));
4503   }
4504   /* Handle DMPlex refinement */
4505   remap = PETSC_TRUE;
4506   PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
4507   PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
4508   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
4509   if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4510   if (refine && isHierarchy) {
4511     DM *dms, coarseDM;
4512 
4513     PetscCall(DMGetCoarseDM(dm, &coarseDM));
4514     PetscCall(PetscObjectReference((PetscObject)coarseDM));
4515     PetscCall(PetscMalloc1(refine, &dms));
4516     PetscCall(DMRefineHierarchy(dm, refine, dms));
4517     /* Total hack since we do not pass in a pointer */
4518     PetscCall(DMPlexSwap_Static(dm, dms[refine - 1]));
4519     if (refine == 1) {
4520       PetscCall(DMSetCoarseDM(dm, dms[0]));
4521       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4522     } else {
4523       PetscCall(DMSetCoarseDM(dm, dms[refine - 2]));
4524       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
4525       PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1]));
4526       PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE));
4527     }
4528     PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM));
4529     PetscCall(PetscObjectDereference((PetscObject)coarseDM));
4530     /* Free DMs */
4531     for (r = 0; r < refine; ++r) {
4532       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4533       PetscCall(DMDestroy(&dms[r]));
4534     }
4535     PetscCall(PetscFree(dms));
4536   } else {
4537     for (r = 0; r < refine; ++r) {
4538       DM             rdm;
4539       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;
4540 
4541       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4542       PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
4543       /* Total hack since we do not pass in a pointer */
4544       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4545       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4546       if (coordFunc && remap) {
4547         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4548         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4549       }
4550     }
4551   }
4552   /* Handle DMPlex coarsening */
4553   PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0));
4554   PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0));
4555   if (coarsen && isHierarchy) {
4556     DM *dms;
4557 
4558     PetscCall(PetscMalloc1(coarsen, &dms));
4559     PetscCall(DMCoarsenHierarchy(dm, coarsen, dms));
4560     /* Free DMs */
4561     for (r = 0; r < coarsen; ++r) {
4562       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
4563       PetscCall(DMDestroy(&dms[r]));
4564     }
4565     PetscCall(PetscFree(dms));
4566   } else {
4567     for (r = 0; r < coarsen; ++r) {
4568       DM             cdm;
4569       PetscPointFunc coordFunc = ((DM_Plex *)dm->data)->coordFunc;
4570 
4571       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4572       PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm));
4573       /* Total hack since we do not pass in a pointer */
4574       PetscCall(DMPlexReplace_Internal(dm, &cdm));
4575       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4576       if (coordFunc) {
4577         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
4578         ((DM_Plex *)dm->data)->coordFunc = coordFunc;
4579       }
4580     }
4581   }
4582   // Handle coordinate remapping
4583   remap = PETSC_FALSE;
4584   PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL));
4585   if (remap) {
4586     DMPlexCoordMap map     = DM_COORD_MAP_NONE;
4587     PetscPointFunc mapFunc = NULL;
4588     PetscScalar    params[16];
4589     PetscInt       Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim;
4590     MPI_Comm       comm;
4591 
4592     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4593     PetscCall(DMGetCoordinateDim(dm, &cdim));
4594     PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg));
4595     if (!flg) Np = 0;
4596     // TODO Allow user to pass a map function by name
4597     PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg));
4598     if (flg) {
4599       switch (map) {
4600       case DM_COORD_MAP_NONE:
4601         mapFunc = coordMap_identity;
4602         break;
4603       case DM_COORD_MAP_SHEAR:
4604         mapFunc = coordMap_shear;
4605         if (!Np) {
4606           Np        = cdim + 1;
4607           params[0] = 0;
4608           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
4609         }
4610         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The shear coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
4611         break;
4612       case DM_COORD_MAP_FLARE:
4613         mapFunc = coordMap_flare;
4614         if (!Np) {
4615           Np        = cdim + 1;
4616           params[0] = 0;
4617           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
4618         }
4619         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The flare coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
4620         break;
4621       case DM_COORD_MAP_ANNULUS:
4622         mapFunc = coordMap_annulus;
4623         if (!Np) {
4624           Np        = 2;
4625           params[0] = 1.;
4626           params[1] = 2.;
4627         }
4628         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
4629         break;
4630       case DM_COORD_MAP_SHELL:
4631         mapFunc = coordMap_shell;
4632         if (!Np) {
4633           Np        = 2;
4634           params[0] = 1.;
4635           params[1] = 2.;
4636         }
4637         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
4638         break;
4639       default:
4640         mapFunc = coordMap_identity;
4641       }
4642     }
4643     if (Np) {
4644       DM      cdm;
4645       PetscDS cds;
4646 
4647       PetscCall(DMGetCoordinateDM(dm, &cdm));
4648       PetscCall(DMGetDS(cdm, &cds));
4649       PetscCall(PetscDSSetConstants(cds, Np, params));
4650     }
4651     PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc));
4652   }
4653   /* Handle ghost cells */
4654   PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL));
4655   if (ghostCells) {
4656     DM   gdm;
4657     char lname[PETSC_MAX_PATH_LEN];
4658 
4659     lname[0] = '\0';
4660     PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg));
4661     PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm));
4662     PetscCall(DMPlexReplace_Internal(dm, &gdm));
4663   }
4664   /* Handle 1D order */
4665   if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) {
4666     DM           cdm, rdm;
4667     PetscDS      cds;
4668     PetscObject  obj;
4669     PetscClassId id = PETSC_OBJECT_CLASSID;
4670     IS           perm;
4671     PetscInt     Nf;
4672     PetscBool    distributed;
4673 
4674     PetscCall(DMPlexIsDistributed(dm, &distributed));
4675     PetscCall(DMGetCoordinateDM(dm, &cdm));
4676     PetscCall(DMGetDS(cdm, &cds));
4677     PetscCall(PetscDSGetNumFields(cds, &Nf));
4678     if (Nf) {
4679       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
4680       PetscCall(PetscObjectGetClassId(obj, &id));
4681     }
4682     if (!distributed && id != PETSCFE_CLASSID) {
4683       PetscCall(DMPlexGetOrdering1D(dm, &perm));
4684       PetscCall(DMPlexPermute(dm, perm, &rdm));
4685       PetscCall(DMPlexReplace_Internal(dm, &rdm));
4686       PetscCall(ISDestroy(&perm));
4687     }
4688   }
4689 /* Handle */
4690 non_refine:
4691   PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
4692   PetscOptionsHeadEnd();
4693   PetscFunctionReturn(PETSC_SUCCESS);
4694 }
4695 
4696 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec)
4697 {
4698   PetscFunctionBegin;
4699   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
4700   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
4701   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex));
4702   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_Plex_Native));
4703   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex));
4704   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_Plex_Native));
4705   PetscFunctionReturn(PETSC_SUCCESS);
4706 }
4707 
4708 static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec)
4709 {
4710   PetscFunctionBegin;
4711   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
4712   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Plex_Local));
4713   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_Plex_Local));
4714   PetscFunctionReturn(PETSC_SUCCESS);
4715 }
4716 
4717 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4718 {
4719   PetscInt depth, d;
4720 
4721   PetscFunctionBegin;
4722   PetscCall(DMPlexGetDepth(dm, &depth));
4723   if (depth == 1) {
4724     PetscCall(DMGetDimension(dm, &d));
4725     if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4726     else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd));
4727     else {
4728       *pStart = 0;
4729       *pEnd   = 0;
4730     }
4731   } else {
4732     PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
4733   }
4734   PetscFunctionReturn(PETSC_SUCCESS);
4735 }
4736 
4737 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
4738 {
4739   PetscSF            sf;
4740   PetscInt           niranks, njranks, n;
4741   const PetscMPIInt *iranks, *jranks;
4742   DM_Plex           *data = (DM_Plex *)dm->data;
4743 
4744   PetscFunctionBegin;
4745   PetscCall(DMGetPointSF(dm, &sf));
4746   if (!data->neighbors) {
4747     PetscCall(PetscSFSetUp(sf));
4748     PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL));
4749     PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL));
4750     PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors));
4751     PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks));
4752     PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks));
4753     n = njranks + niranks;
4754     PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1));
4755     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
4756     PetscCall(PetscMPIIntCast(n, data->neighbors));
4757   }
4758   if (nranks) *nranks = data->neighbors[0];
4759   if (ranks) {
4760     if (data->neighbors[0]) *ranks = data->neighbors + 1;
4761     else *ranks = NULL;
4762   }
4763   PetscFunctionReturn(PETSC_SUCCESS);
4764 }
4765 
4766 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec);
4767 
4768 static PetscErrorCode DMInitialize_Plex(DM dm)
4769 {
4770   PetscFunctionBegin;
4771   dm->ops->view                      = DMView_Plex;
4772   dm->ops->load                      = DMLoad_Plex;
4773   dm->ops->setfromoptions            = DMSetFromOptions_Plex;
4774   dm->ops->clone                     = DMClone_Plex;
4775   dm->ops->setup                     = DMSetUp_Plex;
4776   dm->ops->createlocalsection        = DMCreateLocalSection_Plex;
4777   dm->ops->createsectionpermutation  = DMCreateSectionPermutation_Plex;
4778   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_Plex;
4779   dm->ops->createglobalvector        = DMCreateGlobalVector_Plex;
4780   dm->ops->createlocalvector         = DMCreateLocalVector_Plex;
4781   dm->ops->getlocaltoglobalmapping   = NULL;
4782   dm->ops->createfieldis             = NULL;
4783   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_Plex;
4784   dm->ops->createcoordinatefield     = DMCreateCoordinateField_Plex;
4785   dm->ops->getcoloring               = NULL;
4786   dm->ops->creatematrix              = DMCreateMatrix_Plex;
4787   dm->ops->createinterpolation       = DMCreateInterpolation_Plex;
4788   dm->ops->createmassmatrix          = DMCreateMassMatrix_Plex;
4789   dm->ops->createmassmatrixlumped    = DMCreateMassMatrixLumped_Plex;
4790   dm->ops->createinjection           = DMCreateInjection_Plex;
4791   dm->ops->refine                    = DMRefine_Plex;
4792   dm->ops->coarsen                   = DMCoarsen_Plex;
4793   dm->ops->refinehierarchy           = DMRefineHierarchy_Plex;
4794   dm->ops->coarsenhierarchy          = DMCoarsenHierarchy_Plex;
4795   dm->ops->extrude                   = DMExtrude_Plex;
4796   dm->ops->globaltolocalbegin        = NULL;
4797   dm->ops->globaltolocalend          = NULL;
4798   dm->ops->localtoglobalbegin        = NULL;
4799   dm->ops->localtoglobalend          = NULL;
4800   dm->ops->destroy                   = DMDestroy_Plex;
4801   dm->ops->createsubdm               = DMCreateSubDM_Plex;
4802   dm->ops->createsuperdm             = DMCreateSuperDM_Plex;
4803   dm->ops->getdimpoints              = DMGetDimPoints_Plex;
4804   dm->ops->locatepoints              = DMLocatePoints_Plex;
4805   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_Plex;
4806   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex;
4807   dm->ops->projectfieldlocal         = DMProjectFieldLocal_Plex;
4808   dm->ops->projectfieldlabellocal    = DMProjectFieldLabelLocal_Plex;
4809   dm->ops->projectbdfieldlabellocal  = DMProjectBdFieldLabelLocal_Plex;
4810   dm->ops->computel2diff             = DMComputeL2Diff_Plex;
4811   dm->ops->computel2gradientdiff     = DMComputeL2GradientDiff_Plex;
4812   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_Plex;
4813   dm->ops->getneighbors              = DMGetNeighbors_Plex;
4814   dm->ops->getlocalboundingbox       = DMGetLocalBoundingBox_Coordinates;
4815   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex;
4816   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_Plex;
4817   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex));
4818   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex));
4819   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex));
4820   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex));
4821   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex));
4822   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex));
4823   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex));
4824   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex));
4825   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex));
4826   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex));
4827   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex));
4828   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex));
4829   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex));
4830   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
4831   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex));
4832   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex));
4833   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex));
4834   PetscFunctionReturn(PETSC_SUCCESS);
4835 }
4836 
4837 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
4838 {
4839   DM_Plex       *mesh = (DM_Plex *)dm->data;
4840   const PetscSF *face_sfs;
4841   PetscInt       num_face_sfs;
4842 
4843   PetscFunctionBegin;
4844   mesh->refct++;
4845   (*newdm)->data = mesh;
4846   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs));
4847   PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs));
4848   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX));
4849   PetscCall(DMInitialize_Plex(*newdm));
4850   PetscFunctionReturn(PETSC_SUCCESS);
4851 }
4852 
4853 /*MC
4854   DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
4855                     In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is
4856                     specified by a PetscSection object. Ownership in the global representation is determined by
4857                     ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object.
4858 
4859   Options Database Keys:
4860 + -dm_refine_pre                     - Refine mesh before distribution
4861 + -dm_refine_uniform_pre             - Choose uniform or generator-based refinement
4862 + -dm_refine_volume_limit_pre        - Cell volume limit after pre-refinement using generator
4863 . -dm_distribute                     - Distribute mesh across processes
4864 . -dm_distribute_overlap             - Number of cells to overlap for distribution
4865 . -dm_refine                         - Refine mesh after distribution
4866 . -dm_localize <bool>                - Whether to localize coordinates for periodic meshes
4867 . -dm_sparse_localize <bool>         - Whether to only localize cells on the periodic boundary
4868 . -dm_plex_hash_location             - Use grid hashing for point location
4869 . -dm_plex_hash_box_faces <n,m,p>    - The number of divisions in each direction of the grid hash
4870 . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
4871 . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
4872 . -dm_plex_max_projection_height     - Maximum mesh point height used to project locally
4873 . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
4874 . -dm_plex_reorder_section           - Use specialized blocking if available
4875 . -dm_plex_check_all                 - Perform all checks below
4876 . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
4877 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
4878 . -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
4879 . -dm_plex_check_geometry            - Check that cells have positive volume
4880 . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
4881 . -dm_plex_view_scale <num>          - Scale the TikZ
4882 . -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
4883 - -dm_plex_print_fvm <num>           - View FVM assembly information, such as flux updates
4884 
4885   Level: intermediate
4886 
4887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection`
4888 M*/
4889 
4890 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
4891 {
4892   DM_Plex *mesh;
4893   PetscInt unit;
4894 
4895   PetscFunctionBegin;
4896   PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite));
4897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4898   PetscCall(PetscNew(&mesh));
4899   dm->reorderSection = DM_REORDER_DEFAULT_NOTSET;
4900   dm->data           = mesh;
4901 
4902   mesh->refct = 1;
4903   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection));
4904   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection));
4905   mesh->refinementUniform      = PETSC_TRUE;
4906   mesh->refinementLimit        = -1.0;
4907   mesh->distDefault            = PETSC_TRUE;
4908   mesh->reorderDefault         = DM_REORDER_DEFAULT_NOTSET;
4909   mesh->distributionName       = NULL;
4910   mesh->interpolated           = DMPLEX_INTERPOLATED_INVALID;
4911   mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID;
4912 
4913   PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner));
4914   mesh->remeshBd = PETSC_FALSE;
4915 
4916   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
4917 
4918   mesh->depthState    = -1;
4919   mesh->celltypeState = -1;
4920   mesh->printTol      = 1.0e-10;
4921 
4922   PetscCall(DMInitialize_Plex(dm));
4923   PetscFunctionReturn(PETSC_SUCCESS);
4924 }
4925 
4926 /*@
4927   DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
4928 
4929   Collective
4930 
4931   Input Parameter:
4932 . comm - The communicator for the `DMPLEX` object
4933 
4934   Output Parameter:
4935 . mesh - The `DMPLEX` object
4936 
4937   Level: beginner
4938 
4939 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()`
4940 @*/
4941 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
4942 {
4943   PetscFunctionBegin;
4944   PetscAssertPointer(mesh, 2);
4945   PetscCall(DMCreate(comm, mesh));
4946   PetscCall(DMSetType(*mesh, DMPLEX));
4947   PetscFunctionReturn(PETSC_SUCCESS);
4948 }
4949 
4950 /*@C
4951   DMPlexBuildFromCellListParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)
4952 
4953   Collective; No Fortran Support
4954 
4955   Input Parameters:
4956 + dm          - The `DM`
4957 . numCells    - The number of cells owned by this process
4958 . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
4959 . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
4960 . numCorners  - The number of vertices for each cell
4961 - cells       - An array of numCells*numCorners numbers, the global vertex numbers for each cell
4962 
4963   Output Parameters:
4964 + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
4965 - verticesAdjSaved - (Optional) vertex adjacency array
4966 
4967   Level: advanced
4968 
4969   Notes:
4970   Two triangles sharing a face
4971 .vb
4972 
4973         2
4974       / | \
4975      /  |  \
4976     /   |   \
4977    0  0 | 1  3
4978     \   |   /
4979      \  |  /
4980       \ | /
4981         1
4982 .ve
4983   would have input
4984 .vb
4985   numCells = 2, numVertices = 4
4986   cells = [0 1 2  1 3 2]
4987 .ve
4988   which would result in the `DMPLEX`
4989 .vb
4990 
4991         4
4992       / | \
4993      /  |  \
4994     /   |   \
4995    2  0 | 1  5
4996     \   |   /
4997      \  |  /
4998       \ | /
4999         3
5000 .ve
5001 
5002   Vertices are implicitly numbered consecutively 0,...,NVertices.
5003   Each rank owns a chunk of numVertices consecutive vertices.
5004   If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout.
5005   If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
5006   If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks.
5007 
5008   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
5009 
5010 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
5011           `PetscSF`
5012 @*/
5013 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF, PetscInt **verticesAdjSaved)
5014 {
5015   PetscSF     sfPoint;
5016   PetscLayout layout;
5017   PetscInt    numVerticesAdj, *verticesAdj, *cones, c, p;
5018 
5019   PetscFunctionBegin;
5020   PetscValidLogicalCollectiveInt(dm, NVertices, 4);
5021   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5022   /* Get/check global number of vertices */
5023   {
5024     PetscInt       NVerticesInCells, i;
5025     const PetscInt len = numCells * numCorners;
5026 
5027     /* NVerticesInCells = max(cells) + 1 */
5028     NVerticesInCells = PETSC_MIN_INT;
5029     for (i = 0; i < len; i++)
5030       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5031     ++NVerticesInCells;
5032     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
5033 
5034     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
5035     else
5036       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);
5037   }
5038   /* Count locally unique vertices */
5039   {
5040     PetscHSetI vhash;
5041     PetscInt   off = 0;
5042 
5043     PetscCall(PetscHSetICreate(&vhash));
5044     for (c = 0; c < numCells; ++c) {
5045       for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p]));
5046     }
5047     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
5048     if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
5049     else verticesAdj = *verticesAdjSaved;
5050     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
5051     PetscCall(PetscHSetIDestroy(&vhash));
5052     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
5053   }
5054   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
5055   /* Create cones */
5056   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
5057   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
5058   PetscCall(DMSetUp(dm));
5059   PetscCall(DMPlexGetCones(dm, &cones));
5060   for (c = 0; c < numCells; ++c) {
5061     for (p = 0; p < numCorners; ++p) {
5062       const PetscInt gv = cells[c * numCorners + p];
5063       PetscInt       lv;
5064 
5065       /* Positions within verticesAdj form 0-based local vertex numbering;
5066          we need to shift it by numCells to get correct DAG points (cells go first) */
5067       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
5068       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
5069       cones[c * numCorners + p] = lv + numCells;
5070     }
5071   }
5072   /* Build point sf */
5073   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
5074   PetscCall(PetscLayoutSetSize(layout, NVertices));
5075   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
5076   PetscCall(PetscLayoutSetBlockSize(layout, 1));
5077   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
5078   PetscCall(PetscLayoutDestroy(&layout));
5079   if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj));
5080   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
5081   if (dm->sf) {
5082     const char *prefix;
5083 
5084     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
5085     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
5086   }
5087   PetscCall(DMSetPointSF(dm, sfPoint));
5088   PetscCall(PetscSFDestroy(&sfPoint));
5089   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
5090   /* Fill in the rest of the topology structure */
5091   PetscCall(DMPlexSymmetrize(dm));
5092   PetscCall(DMPlexStratify(dm));
5093   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5094   PetscFunctionReturn(PETSC_SUCCESS);
5095 }
5096 
5097 /*@C
5098   DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
5099 
5100   Collective; No Fortran Support
5101 
5102   Input Parameters:
5103 + dm           - The `DM`
5104 . spaceDim     - The spatial dimension used for coordinates
5105 . sfVert       - `PetscSF` describing complete vertex ownership
5106 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
5107 
5108   Level: advanced
5109 
5110 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()`
5111 @*/
5112 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
5113 {
5114   PetscSection coordSection;
5115   Vec          coordinates;
5116   PetscScalar *coords;
5117   PetscInt     numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;
5118 
5119   PetscFunctionBegin;
5120   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5121   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5122   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
5123   PetscCall(DMSetCoordinateDim(dm, spaceDim));
5124   PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL));
5125   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);
5126   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5127   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5128   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
5129   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
5130   for (v = vStart; v < vEnd; ++v) {
5131     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
5132     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
5133   }
5134   PetscCall(PetscSectionSetUp(coordSection));
5135   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5136   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
5137   PetscCall(VecSetBlockSize(coordinates, spaceDim));
5138   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5139   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5140   PetscCall(VecSetType(coordinates, VECSTANDARD));
5141   PetscCall(VecGetArray(coordinates, &coords));
5142   {
5143     MPI_Datatype coordtype;
5144 
5145     /* Need a temp buffer for coords if we have complex/single */
5146     PetscCallMPI(MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype));
5147     PetscCallMPI(MPI_Type_commit(&coordtype));
5148 #if defined(PETSC_USE_COMPLEX)
5149     {
5150       PetscScalar *svertexCoords;
5151       PetscInt     i;
5152       PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords));
5153       for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i];
5154       PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
5155       PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
5156       PetscCall(PetscFree(svertexCoords));
5157     }
5158 #else
5159     PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
5160     PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
5161 #endif
5162     PetscCallMPI(MPI_Type_free(&coordtype));
5163   }
5164   PetscCall(VecRestoreArray(coordinates, &coords));
5165   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5166   PetscCall(VecDestroy(&coordinates));
5167   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5168   PetscFunctionReturn(PETSC_SUCCESS);
5169 }
5170 
5171 /*@
5172   DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output)
5173 
5174   Collective
5175 
5176   Input Parameters:
5177 + comm         - The communicator
5178 . dim          - The topological dimension of the mesh
5179 . numCells     - The number of cells owned by this process
5180 . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
5181 . NVertices    - The global number of vertices, or `PETSC_DECIDE`
5182 . numCorners   - The number of vertices for each cell
5183 . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
5184 . cells        - An array of numCells*numCorners numbers, the global vertex numbers for each cell
5185 . spaceDim     - The spatial dimension used for coordinates
5186 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
5187 
5188   Output Parameters:
5189 + dm          - The `DM`
5190 . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
5191 - verticesAdj - (Optional) vertex adjacency array
5192 
5193   Level: intermediate
5194 
5195   Notes:
5196   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
5197   `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`
5198 
5199   See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters.
5200 
5201   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.
5202 
5203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
5204 @*/
5205 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)
5206 {
5207   PetscSF sfVert;
5208 
5209   PetscFunctionBegin;
5210   PetscCall(DMCreate(comm, dm));
5211   PetscCall(DMSetType(*dm, DMPLEX));
5212   PetscValidLogicalCollectiveInt(*dm, dim, 2);
5213   PetscValidLogicalCollectiveInt(*dm, spaceDim, 9);
5214   PetscCall(DMSetDimension(*dm, dim));
5215   PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj));
5216   if (interpolate) {
5217     DM idm;
5218 
5219     PetscCall(DMPlexInterpolate(*dm, &idm));
5220     PetscCall(DMDestroy(dm));
5221     *dm = idm;
5222   }
5223   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
5224   if (vertexSF) *vertexSF = sfVert;
5225   else PetscCall(PetscSFDestroy(&sfVert));
5226   PetscFunctionReturn(PETSC_SUCCESS);
5227 }
5228 
5229 /*@C
5230   DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)
5231 
5232   Collective; No Fortran Support
5233 
5234   Input Parameters:
5235 + dm          - The `DM`
5236 . numCells    - The number of cells owned by this process
5237 . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE`
5238 . numCorners  - The number of vertices for each cell
5239 - cells       - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell
5240 
5241   Level: advanced
5242 
5243   Notes:
5244   Two triangles sharing a face
5245 .vb
5246 
5247         2
5248       / | \
5249      /  |  \
5250     /   |   \
5251    0  0 | 1  3
5252     \   |   /
5253      \  |  /
5254       \ | /
5255         1
5256 .ve
5257   would have input
5258 .vb
5259   numCells = 2, numVertices = 4
5260   cells = [0 1 2  1 3 2]
5261 .ve
5262   which would result in the `DMPLEX`
5263 .vb
5264 
5265         4
5266       / | \
5267      /  |  \
5268     /   |   \
5269    2  0 | 1  5
5270     \   |   /
5271      \  |  /
5272       \ | /
5273         3
5274 .ve
5275 
5276   If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1.
5277 
5278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()`
5279 @*/
5280 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
5281 {
5282   PetscInt *cones, c, p, dim;
5283 
5284   PetscFunctionBegin;
5285   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5286   PetscCall(DMGetDimension(dm, &dim));
5287   /* Get/check global number of vertices */
5288   {
5289     PetscInt       NVerticesInCells, i;
5290     const PetscInt len = numCells * numCorners;
5291 
5292     /* NVerticesInCells = max(cells) + 1 */
5293     NVerticesInCells = PETSC_MIN_INT;
5294     for (i = 0; i < len; i++)
5295       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
5296     ++NVerticesInCells;
5297 
5298     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
5299     else
5300       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);
5301   }
5302   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
5303   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
5304   PetscCall(DMSetUp(dm));
5305   PetscCall(DMPlexGetCones(dm, &cones));
5306   for (c = 0; c < numCells; ++c) {
5307     for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells;
5308   }
5309   PetscCall(DMPlexSymmetrize(dm));
5310   PetscCall(DMPlexStratify(dm));
5311   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
5312   PetscFunctionReturn(PETSC_SUCCESS);
5313 }
5314 
5315 /*@C
5316   DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
5317 
5318   Collective; No Fortran Support
5319 
5320   Input Parameters:
5321 + dm           - The `DM`
5322 . spaceDim     - The spatial dimension used for coordinates
5323 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
5324 
5325   Level: advanced
5326 
5327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()`
5328 @*/
5329 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
5330 {
5331   PetscSection coordSection;
5332   Vec          coordinates;
5333   DM           cdm;
5334   PetscScalar *coords;
5335   PetscInt     v, vStart, vEnd, d;
5336 
5337   PetscFunctionBegin;
5338   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5339   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
5340   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
5341   PetscCall(DMSetCoordinateDim(dm, spaceDim));
5342   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5343   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5344   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
5345   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
5346   for (v = vStart; v < vEnd; ++v) {
5347     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
5348     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
5349   }
5350   PetscCall(PetscSectionSetUp(coordSection));
5351 
5352   PetscCall(DMGetCoordinateDM(dm, &cdm));
5353   PetscCall(DMCreateLocalVector(cdm, &coordinates));
5354   PetscCall(VecSetBlockSize(coordinates, spaceDim));
5355   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5356   PetscCall(VecGetArrayWrite(coordinates, &coords));
5357   for (v = 0; v < vEnd - vStart; ++v) {
5358     for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d];
5359   }
5360   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
5361   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5362   PetscCall(VecDestroy(&coordinates));
5363   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
5364   PetscFunctionReturn(PETSC_SUCCESS);
5365 }
5366 
5367 /*@
5368   DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input
5369 
5370   Collective
5371 
5372   Input Parameters:
5373 + comm         - The communicator
5374 . dim          - The topological dimension of the mesh
5375 . numCells     - The number of cells, only on process 0
5376 . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0
5377 . numCorners   - The number of vertices for each cell, only on process 0
5378 . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
5379 . cells        - An array of numCells*numCorners numbers, the vertices for each cell, only on process 0
5380 . spaceDim     - The spatial dimension used for coordinates
5381 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex, only on process 0
5382 
5383   Output Parameter:
5384 . dm - The `DM`, which only has points on process 0
5385 
5386   Level: intermediate
5387 
5388   Notes:
5389   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`,
5390   `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()`
5391 
5392   See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters.
5393   See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters.
5394   See `DMPlexCreateFromCellListParallelPetsc()` for parallel input
5395 
5396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
5397 @*/
5398 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)
5399 {
5400   PetscMPIInt rank;
5401 
5402   PetscFunctionBegin;
5403   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.");
5404   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5405   PetscCall(DMCreate(comm, dm));
5406   PetscCall(DMSetType(*dm, DMPLEX));
5407   PetscCall(DMSetDimension(*dm, dim));
5408   if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells));
5409   else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL));
5410   if (interpolate) {
5411     DM idm;
5412 
5413     PetscCall(DMPlexInterpolate(*dm, &idm));
5414     PetscCall(DMDestroy(dm));
5415     *dm = idm;
5416   }
5417   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords));
5418   else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL));
5419   PetscFunctionReturn(PETSC_SUCCESS);
5420 }
5421 
5422 /*@
5423   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM`
5424 
5425   Input Parameters:
5426 + dm               - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()`
5427 . depth            - The depth of the DAG
5428 . numPoints        - Array of size depth + 1 containing the number of points at each `depth`
5429 . coneSize         - The cone size of each point
5430 . cones            - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
5431 . coneOrientations - The orientation of each cone point
5432 - vertexCoords     - An array of `numPoints`[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via `DMSetCoordinateDim()`
5433 
5434   Output Parameter:
5435 . dm - The `DM`
5436 
5437   Level: advanced
5438 
5439   Note:
5440   Two triangles sharing a face would have input
5441 .vb
5442   depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
5443   cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
5444  vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
5445 .ve
5446   which would result in the DMPlex
5447 .vb
5448         4
5449       / | \
5450      /  |  \
5451     /   |   \
5452    2  0 | 1  5
5453     \   |   /
5454      \  |  /
5455       \ | /
5456         3
5457 .ve
5458   Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()`
5459 
5460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5461 @*/
5462 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
5463 {
5464   Vec          coordinates;
5465   PetscSection coordSection;
5466   PetscScalar *coords;
5467   PetscInt     coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
5468 
5469   PetscFunctionBegin;
5470   PetscCall(DMGetDimension(dm, &dim));
5471   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
5472   PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim);
5473   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
5474   PetscCall(DMPlexSetChart(dm, pStart, pEnd));
5475   for (p = pStart; p < pEnd; ++p) {
5476     PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart]));
5477     if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart;
5478   }
5479   PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]);
5480   PetscCall(DMSetUp(dm)); /* Allocate space for cones */
5481   for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) {
5482     PetscCall(DMPlexSetCone(dm, p, &cones[off]));
5483     PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off]));
5484   }
5485   PetscCall(DMPlexSymmetrize(dm));
5486   PetscCall(DMPlexStratify(dm));
5487   /* Build coordinates */
5488   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5489   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5490   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed));
5491   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0]));
5492   for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) {
5493     PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed));
5494     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed));
5495   }
5496   PetscCall(PetscSectionSetUp(coordSection));
5497   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5498   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5499   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5500   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5501   PetscCall(VecSetBlockSize(coordinates, dimEmbed));
5502   PetscCall(VecSetType(coordinates, VECSTANDARD));
5503   if (vertexCoords) {
5504     PetscCall(VecGetArray(coordinates, &coords));
5505     for (v = 0; v < numPoints[0]; ++v) {
5506       PetscInt off;
5507 
5508       PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off));
5509       for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d];
5510     }
5511   }
5512   PetscCall(VecRestoreArray(coordinates, &coords));
5513   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5514   PetscCall(VecDestroy(&coordinates));
5515   PetscFunctionReturn(PETSC_SUCCESS);
5516 }
5517 
5518 /*
5519   DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file.
5520 
5521   Collective
5522 
5523 + comm        - The MPI communicator
5524 . filename    - Name of the .dat file
5525 - interpolate - Create faces and edges in the mesh
5526 
5527   Output Parameter:
5528 . dm  - The `DM` object representing the mesh
5529 
5530   Level: beginner
5531 
5532   Note:
5533   The format is the simplest possible:
5534 .vb
5535   dim Ne Nv Nc Nl
5536   v_1 v_2 ... v_Nc
5537   ...
5538   x y z marker_1 ... marker_Nl
5539 .ve
5540 
5541   Developer Note:
5542   Should use a `PetscViewer` not a filename
5543 
5544 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
5545 */
5546 static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
5547 {
5548   DMLabel      marker;
5549   PetscViewer  viewer;
5550   Vec          coordinates;
5551   PetscSection coordSection;
5552   PetscScalar *coords;
5553   char         line[PETSC_MAX_PATH_LEN];
5554   PetscInt     cdim, coordSize, v, c, d;
5555   PetscMPIInt  rank;
5556   int          snum, dim, Nv, Nc, Ncn, Nl;
5557 
5558   PetscFunctionBegin;
5559   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5560   PetscCall(PetscViewerCreate(comm, &viewer));
5561   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
5562   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5563   PetscCall(PetscViewerFileSetName(viewer, filename));
5564   if (rank == 0) {
5565     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING));
5566     snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl);
5567     PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5568   } else {
5569     Nc = Nv = Ncn = Nl = 0;
5570   }
5571   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
5572   cdim = (PetscInt)dim;
5573   PetscCall(DMCreate(comm, dm));
5574   PetscCall(DMSetType(*dm, DMPLEX));
5575   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
5576   PetscCall(DMSetDimension(*dm, (PetscInt)dim));
5577   PetscCall(DMSetCoordinateDim(*dm, cdim));
5578   /* Read topology */
5579   if (rank == 0) {
5580     char     format[PETSC_MAX_PATH_LEN];
5581     PetscInt cone[8];
5582     int      vbuf[8], v;
5583 
5584     for (c = 0; c < Ncn; ++c) {
5585       format[c * 3 + 0] = '%';
5586       format[c * 3 + 1] = 'd';
5587       format[c * 3 + 2] = ' ';
5588     }
5589     format[Ncn * 3 - 1] = '\0';
5590     for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn));
5591     PetscCall(DMSetUp(*dm));
5592     for (c = 0; c < Nc; ++c) {
5593       PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING));
5594       switch (Ncn) {
5595       case 2:
5596         snum = sscanf(line, format, &vbuf[0], &vbuf[1]);
5597         break;
5598       case 3:
5599         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]);
5600         break;
5601       case 4:
5602         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]);
5603         break;
5604       case 6:
5605         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]);
5606         break;
5607       case 8:
5608         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
5609         break;
5610       default:
5611         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn);
5612       }
5613       PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5614       for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc;
5615       /* Hexahedra are inverted */
5616       if (Ncn == 8) {
5617         PetscInt tmp = cone[1];
5618         cone[1]      = cone[3];
5619         cone[3]      = tmp;
5620       }
5621       PetscCall(DMPlexSetCone(*dm, c, cone));
5622     }
5623   }
5624   PetscCall(DMPlexSymmetrize(*dm));
5625   PetscCall(DMPlexStratify(*dm));
5626   /* Read coordinates */
5627   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
5628   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5629   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
5630   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
5631   for (v = Nc; v < Nc + Nv; ++v) {
5632     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
5633     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
5634   }
5635   PetscCall(PetscSectionSetUp(coordSection));
5636   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5637   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5638   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5639   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5640   PetscCall(VecSetBlockSize(coordinates, cdim));
5641   PetscCall(VecSetType(coordinates, VECSTANDARD));
5642   PetscCall(VecGetArray(coordinates, &coords));
5643   if (rank == 0) {
5644     char   format[PETSC_MAX_PATH_LEN];
5645     double x[3];
5646     int    l, val[3];
5647 
5648     if (Nl) {
5649       for (l = 0; l < Nl; ++l) {
5650         format[l * 3 + 0] = '%';
5651         format[l * 3 + 1] = 'd';
5652         format[l * 3 + 2] = ' ';
5653       }
5654       format[Nl * 3 - 1] = '\0';
5655       PetscCall(DMCreateLabel(*dm, "marker"));
5656       PetscCall(DMGetLabel(*dm, "marker", &marker));
5657     }
5658     for (v = 0; v < Nv; ++v) {
5659       PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING));
5660       snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]);
5661       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5662       switch (Nl) {
5663       case 0:
5664         snum = 0;
5665         break;
5666       case 1:
5667         snum = sscanf(line, format, &val[0]);
5668         break;
5669       case 2:
5670         snum = sscanf(line, format, &val[0], &val[1]);
5671         break;
5672       case 3:
5673         snum = sscanf(line, format, &val[0], &val[1], &val[2]);
5674         break;
5675       default:
5676         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl);
5677       }
5678       PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
5679       for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d];
5680       for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l]));
5681     }
5682   }
5683   PetscCall(VecRestoreArray(coordinates, &coords));
5684   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
5685   PetscCall(VecDestroy(&coordinates));
5686   PetscCall(PetscViewerDestroy(&viewer));
5687   if (interpolate) {
5688     DM      idm;
5689     DMLabel bdlabel;
5690 
5691     PetscCall(DMPlexInterpolate(*dm, &idm));
5692     PetscCall(DMDestroy(dm));
5693     *dm = idm;
5694 
5695     if (!Nl) {
5696       PetscCall(DMCreateLabel(*dm, "marker"));
5697       PetscCall(DMGetLabel(*dm, "marker", &bdlabel));
5698       PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel));
5699       PetscCall(DMPlexLabelComplete(*dm, bdlabel));
5700     }
5701   }
5702   PetscFunctionReturn(PETSC_SUCCESS);
5703 }
5704 
5705 /*@C
5706   DMPlexCreateFromFile - This takes a filename and produces a `DM`
5707 
5708   Collective
5709 
5710   Input Parameters:
5711 + comm        - The communicator
5712 . filename    - A file name
5713 . plexname    - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats
5714 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
5715 
5716   Output Parameter:
5717 . dm - The `DM`
5718 
5719   Options Database Key:
5720 . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5
5721 
5722   Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g.
5723 $ -dm_plex_create_viewer_hdf5_collective
5724 
5725   Level: beginner
5726 
5727   Notes:
5728   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
5729   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
5730   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
5731   The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally
5732   calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats.
5733 
5734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()`
5735 @*/
5736 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm)
5737 {
5738   const char  extGmsh[]      = ".msh";
5739   const char  extGmsh2[]     = ".msh2";
5740   const char  extGmsh4[]     = ".msh4";
5741   const char  extCGNS[]      = ".cgns";
5742   const char  extExodus[]    = ".exo";
5743   const char  extExodus_e[]  = ".e";
5744   const char  extGenesis[]   = ".gen";
5745   const char  extFluent[]    = ".cas";
5746   const char  extHDF5[]      = ".h5";
5747   const char  extXDMFHDF5[]  = ".xdmf.h5";
5748   const char  extPLY[]       = ".ply";
5749   const char  extEGADSLite[] = ".egadslite";
5750   const char  extEGADS[]     = ".egads";
5751   const char  extIGES[]      = ".igs";
5752   const char  extSTEP[]      = ".stp";
5753   const char  extCV[]        = ".dat";
5754   size_t      len;
5755   PetscBool   isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSLite, isEGADS, isIGES, isSTEP, isCV, isXDMFHDF5;
5756   PetscMPIInt rank;
5757 
5758   PetscFunctionBegin;
5759   PetscAssertPointer(filename, 2);
5760   if (plexname) PetscAssertPointer(plexname, 3);
5761   PetscAssertPointer(dm, 5);
5762   PetscCall(DMInitializePackage());
5763   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5764   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5765   PetscCall(PetscStrlen(filename, &len));
5766   PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
5767 
5768 #define CheckExtension(extension__, is_extension__) \
5769   do { \
5770     PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \
5771     /* don't count the null-terminator at the end */ \
5772     const size_t ext_len = sizeof(extension__) - 1; \
5773     if (len < ext_len) { \
5774       is_extension__ = PETSC_FALSE; \
5775     } else { \
5776       PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \
5777     } \
5778   } while (0)
5779 
5780   CheckExtension(extGmsh, isGmsh);
5781   CheckExtension(extGmsh2, isGmsh2);
5782   CheckExtension(extGmsh4, isGmsh4);
5783   CheckExtension(extCGNS, isCGNS);
5784   CheckExtension(extExodus, isExodus);
5785   if (!isExodus) CheckExtension(extExodus_e, isExodus);
5786   CheckExtension(extGenesis, isGenesis);
5787   CheckExtension(extFluent, isFluent);
5788   CheckExtension(extHDF5, isHDF5);
5789   CheckExtension(extPLY, isPLY);
5790   CheckExtension(extEGADSLite, isEGADSLite);
5791   CheckExtension(extEGADS, isEGADS);
5792   CheckExtension(extIGES, isIGES);
5793   CheckExtension(extSTEP, isSTEP);
5794   CheckExtension(extCV, isCV);
5795   CheckExtension(extXDMFHDF5, isXDMFHDF5);
5796 
5797 #undef CheckExtension
5798 
5799   if (isGmsh || isGmsh2 || isGmsh4) {
5800     PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm));
5801   } else if (isCGNS) {
5802     PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm));
5803   } else if (isExodus || isGenesis) {
5804     PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm));
5805   } else if (isFluent) {
5806     PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm));
5807   } else if (isHDF5) {
5808     PetscViewer viewer;
5809 
5810     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
5811     PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL));
5812     PetscCall(PetscViewerCreate(comm, &viewer));
5813     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5));
5814     PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_"));
5815     PetscCall(PetscViewerSetFromOptions(viewer));
5816     PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
5817     PetscCall(PetscViewerFileSetName(viewer, filename));
5818 
5819     PetscCall(DMCreate(comm, dm));
5820     PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
5821     PetscCall(DMSetType(*dm, DMPLEX));
5822     if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF));
5823     PetscCall(DMLoad(*dm, viewer));
5824     if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer));
5825     PetscCall(PetscViewerDestroy(&viewer));
5826 
5827     if (interpolate) {
5828       DM idm;
5829 
5830       PetscCall(DMPlexInterpolate(*dm, &idm));
5831       PetscCall(DMDestroy(dm));
5832       *dm = idm;
5833     }
5834   } else if (isPLY) {
5835     PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm));
5836   } else if (isEGADSLite || isEGADS || isIGES || isSTEP) {
5837     if (isEGADSLite) PetscCall(DMPlexCreateEGADSLiteFromFile(comm, filename, dm));
5838     else PetscCall(DMPlexCreateEGADSFromFile(comm, filename, dm));
5839     if (!interpolate) {
5840       DM udm;
5841 
5842       PetscCall(DMPlexUninterpolate(*dm, &udm));
5843       PetscCall(DMDestroy(dm));
5844       *dm = udm;
5845     }
5846   } else if (isCV) {
5847     PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm));
5848   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
5849   PetscCall(PetscStrlen(plexname, &len));
5850   if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
5851   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0));
5852   PetscFunctionReturn(PETSC_SUCCESS);
5853 }
5854 
5855 /*@C
5856   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.
5857 
5858   Input Parameters:
5859 + tr     - The `DMPlexTransform`
5860 - prefix - An options prefix, or NULL
5861 
5862   Output Parameter:
5863 . dm - The `DM`
5864 
5865   Level: beginner
5866 
5867   Notes:
5868   An emphemeral mesh is one that is not stored concretely, as in the default `DMPLEX` implementation, but rather is produced on the fly in response to queries, using information from the transform and the base mesh.
5869 
5870 .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
5871 @*/
5872 PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm)
5873 {
5874   DM           bdm, bcdm, cdm;
5875   Vec          coordinates, coordinatesNew;
5876   PetscSection cs;
5877   PetscInt     dim, cdim, Nl;
5878 
5879   PetscFunctionBegin;
5880   PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm));
5881   PetscCall(DMSetType(*dm, DMPLEX));
5882   ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL;
5883   // Handle coordinates
5884   PetscCall(DMPlexTransformGetDM(tr, &bdm));
5885   PetscCall(DMGetCoordinateDim(bdm, &cdim));
5886   PetscCall(DMSetCoordinateDim(*dm, cdim));
5887   PetscCall(DMGetDimension(bdm, &dim));
5888   PetscCall(DMSetDimension(*dm, dim));
5889   PetscCall(DMGetCoordinateDM(bdm, &bcdm));
5890   PetscCall(DMGetCoordinateDM(*dm, &cdm));
5891   PetscCall(DMCopyDisc(bcdm, cdm));
5892   PetscCall(DMGetLocalSection(cdm, &cs));
5893   PetscCall(PetscSectionSetNumFields(cs, 1));
5894   PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim));
5895   PetscCall(DMGetCoordinatesLocal(bdm, &coordinates));
5896   PetscCall(VecDuplicate(coordinates, &coordinatesNew));
5897   PetscCall(VecCopy(coordinates, coordinatesNew));
5898   PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew));
5899   PetscCall(VecDestroy(&coordinatesNew));
5900 
5901   PetscCall(PetscObjectReference((PetscObject)tr));
5902   PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr));
5903   ((DM_Plex *)(*dm)->data)->tr = tr;
5904   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
5905   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix));
5906   PetscCall(DMSetFromOptions(*dm));
5907 
5908   PetscCall(DMGetNumLabels(bdm, &Nl));
5909   for (PetscInt l = 0; l < Nl; ++l) {
5910     DMLabel     label, labelNew;
5911     const char *lname;
5912     PetscBool   isDepth, isCellType;
5913 
5914     PetscCall(DMGetLabelName(bdm, l, &lname));
5915     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
5916     if (isDepth) continue;
5917     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
5918     if (isCellType) continue;
5919     PetscCall(DMCreateLabel(*dm, lname));
5920     PetscCall(DMGetLabel(bdm, lname, &label));
5921     PetscCall(DMGetLabel(*dm, lname, &labelNew));
5922     PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL));
5923     PetscCall(DMLabelEphemeralSetLabel(labelNew, label));
5924     PetscCall(DMLabelEphemeralSetTransform(labelNew, tr));
5925     PetscCall(DMLabelSetUp(labelNew));
5926   }
5927   PetscFunctionReturn(PETSC_SUCCESS);
5928 }
5929