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