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