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