xref: /petsc/src/dm/impls/plex/plexcreate.c (revision dd239adf90e3c7c412ec51e10f5eb1d39a843e27)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/
3 #include <petsc/private/hashseti.h>          /*I   "petscdmplex.h"   I*/
4 #include <petscsf.h>
5 
6 PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;
7 
8 /*@
9   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.
10 
11   Collective
12 
13   Input Parameters:
14 + comm - The communicator for the DM object
15 . dim - The spatial dimension
16 . simplex - Flag for simplicial cells, otherwise they are tensor product cells
17 . interpolate - Flag to create intermediate mesh pieces (edges, faces)
18 . refinementUniform - Flag for uniform parallel refinement
19 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell
20 
21   Output Parameter:
22 . dm - The DM object
23 
24   Level: beginner
25 
26 .seealso: DMSetType(), DMCreate()
27 @*/
28 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscBool refinementUniform, PetscReal refinementLimit, DM *newdm)
29 {
30   DM             dm;
31   PetscInt       p;
32   PetscMPIInt    rank;
33   PetscErrorCode ierr;
34 
35   PetscFunctionBegin;
36   ierr = DMCreate(comm, &dm);CHKERRQ(ierr);
37   ierr = DMSetType(dm, DMPLEX);CHKERRQ(ierr);
38   ierr = DMSetDimension(dm, dim);CHKERRQ(ierr);
39   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
40   switch (dim) {
41   case 2:
42     if (simplex) {ierr = PetscObjectSetName((PetscObject) dm, "triangular");CHKERRQ(ierr);}
43     else         {ierr = PetscObjectSetName((PetscObject) dm, "quadrilateral");CHKERRQ(ierr);}
44     break;
45   case 3:
46     if (simplex) {ierr = PetscObjectSetName((PetscObject) dm, "tetrahedral");CHKERRQ(ierr);}
47     else         {ierr = PetscObjectSetName((PetscObject) dm, "hexahedral");CHKERRQ(ierr);}
48     break;
49   default:
50     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %D", dim);
51   }
52   if (rank) {
53     PetscInt numPoints[2] = {0, 0};
54     ierr = DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
55   } else {
56     switch (dim) {
57     case 2:
58       if (simplex) {
59         PetscInt    numPoints[2]        = {4, 2};
60         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
61         PetscInt    cones[6]            = {2, 3, 4,  5, 4, 3};
62         PetscInt    coneOrientations[6] = {0, 0, 0,  0, 0, 0};
63         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
64         PetscInt    markerPoints[8]     = {2, 1, 3, 1, 4, 1, 5, 1};
65 
66         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
67         for (p = 0; p < 4; ++p) {ierr = DMSetLabelValue(dm, "marker", markerPoints[p*2], markerPoints[p*2+1]);CHKERRQ(ierr);}
68       } else {
69         PetscInt    numPoints[2]        = {6, 2};
70         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
71         PetscInt    cones[8]            = {2, 3, 4, 5,  3, 6, 7, 4};
72         PetscInt    coneOrientations[8] = {0, 0, 0, 0,  0, 0, 0, 0};
73         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};
74 
75         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
76       }
77       break;
78     case 3:
79       if (simplex) {
80         PetscInt    numPoints[2]        = {5, 2};
81         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
82         PetscInt    cones[8]            = {4, 3, 5, 2,  5, 3, 4, 6};
83         PetscInt    coneOrientations[8] = {0, 0, 0, 0,  0, 0, 0, 0};
84         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};
85         PetscInt    markerPoints[10]    = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1};
86 
87         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
88         for (p = 0; p < 5; ++p) {ierr = DMSetLabelValue(dm, "marker", markerPoints[p*2], markerPoints[p*2+1]);CHKERRQ(ierr);}
89       } else {
90         PetscInt    numPoints[2]         = {12, 2};
91         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
92         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9,  5, 4, 10, 11, 7, 12, 13, 8};
93         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0,  0, 0,  0,  0, 0,  0,  0, 0};
94         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,
95                                             -1.0, -0.5,  0.5,   0.0, -0.5,  0.5,  0.0,  0.5,  0.5,  -1.0,  0.5,  0.5,
96                                              1.0,  0.5, -0.5,   1.0, -0.5, -0.5,  1.0, -0.5,  0.5,   1.0,  0.5,  0.5};
97 
98         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
99       }
100       break;
101     default:
102       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %D", dim);
103     }
104   }
105   *newdm = dm;
106   if (refinementLimit > 0.0) {
107     DM rdm;
108     const char *name;
109 
110     ierr = DMPlexSetRefinementUniform(*newdm, PETSC_FALSE);CHKERRQ(ierr);
111     ierr = DMPlexSetRefinementLimit(*newdm, refinementLimit);CHKERRQ(ierr);
112     ierr = DMRefine(*newdm, comm, &rdm);CHKERRQ(ierr);
113     ierr = PetscObjectGetName((PetscObject) *newdm, &name);CHKERRQ(ierr);
114     ierr = PetscObjectSetName((PetscObject)    rdm,  name);CHKERRQ(ierr);
115     ierr = DMDestroy(newdm);CHKERRQ(ierr);
116     *newdm = rdm;
117   }
118   if (interpolate) {
119     DM idm;
120 
121     ierr = DMPlexInterpolate(*newdm, &idm);CHKERRQ(ierr);
122     ierr = DMDestroy(newdm);CHKERRQ(ierr);
123     *newdm = idm;
124   }
125   {
126     DM refinedMesh     = NULL;
127     DM distributedMesh = NULL;
128 
129     /* Distribute mesh over processes */
130     ierr = DMPlexDistribute(*newdm, 0, NULL, &distributedMesh);CHKERRQ(ierr);
131     if (distributedMesh) {
132       ierr = DMDestroy(newdm);CHKERRQ(ierr);
133       *newdm = distributedMesh;
134     }
135     if (refinementUniform) {
136       ierr = DMPlexSetRefinementUniform(*newdm, refinementUniform);CHKERRQ(ierr);
137       ierr = DMRefine(*newdm, comm, &refinedMesh);CHKERRQ(ierr);
138       if (refinedMesh) {
139         ierr = DMDestroy(newdm);CHKERRQ(ierr);
140         *newdm = refinedMesh;
141       }
142     }
143   }
144   PetscFunctionReturn(0);
145 }
146 
147 /*@
148   DMPlexCreateSquareBoundary - Creates a 1D mesh the is the boundary of a square lattice.
149 
150   Collective
151 
152   Input Parameters:
153 + comm  - The communicator for the DM object
154 . lower - The lower left corner coordinates
155 . upper - The upper right corner coordinates
156 - edges - The number of cells in each direction
157 
158   Output Parameter:
159 . dm  - The DM object
160 
161   Note: Here is the numbering returned for 2 cells in each direction:
162 $ 18--5-17--4--16
163 $  |     |     |
164 $  6    10     3
165 $  |     |     |
166 $ 19-11-20--9--15
167 $  |     |     |
168 $  7     8     2
169 $  |     |     |
170 $ 12--0-13--1--14
171 
172   Level: beginner
173 
174 .seealso: DMPlexCreateBoxMesh(), DMPlexCreateCubeBoundary(), DMSetType(), DMCreate()
175 @*/
176 PetscErrorCode DMPlexCreateSquareBoundary(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
177 {
178   const PetscInt numVertices    = (edges[0]+1)*(edges[1]+1);
179   const PetscInt numEdges       = edges[0]*(edges[1]+1) + (edges[0]+1)*edges[1];
180   PetscInt       markerTop      = 1;
181   PetscInt       markerBottom   = 1;
182   PetscInt       markerRight    = 1;
183   PetscInt       markerLeft     = 1;
184   PetscBool      markerSeparate = PETSC_FALSE;
185   Vec            coordinates;
186   PetscSection   coordSection;
187   PetscScalar    *coords;
188   PetscInt       coordSize;
189   PetscMPIInt    rank;
190   PetscInt       v, vx, vy;
191   PetscErrorCode ierr;
192 
193   PetscFunctionBegin;
194   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL);CHKERRQ(ierr);
195   if (markerSeparate) {
196     markerTop    = 3;
197     markerBottom = 1;
198     markerRight  = 2;
199     markerLeft   = 4;
200   }
201   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
202   if (!rank) {
203     PetscInt e, ex, ey;
204 
205     ierr = DMPlexSetChart(dm, 0, numEdges+numVertices);CHKERRQ(ierr);
206     for (e = 0; e < numEdges; ++e) {
207       ierr = DMPlexSetConeSize(dm, e, 2);CHKERRQ(ierr);
208     }
209     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
210     for (vx = 0; vx <= edges[0]; vx++) {
211       for (ey = 0; ey < edges[1]; ey++) {
212         PetscInt edge   = vx*edges[1] + ey + edges[0]*(edges[1]+1);
213         PetscInt vertex = ey*(edges[0]+1) + vx + numEdges;
214         PetscInt cone[2];
215 
216         cone[0] = vertex; cone[1] = vertex+edges[0]+1;
217         ierr    = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
218         if (vx == edges[0]) {
219           ierr = DMSetLabelValue(dm, "marker", edge,    markerRight);CHKERRQ(ierr);
220           ierr = DMSetLabelValue(dm, "marker", cone[0], markerRight);CHKERRQ(ierr);
221           if (ey == edges[1]-1) {
222             ierr = DMSetLabelValue(dm, "marker", cone[1], markerRight);CHKERRQ(ierr);
223             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerRight);CHKERRQ(ierr);
224           }
225         } else if (vx == 0) {
226           ierr = DMSetLabelValue(dm, "marker", edge,    markerLeft);CHKERRQ(ierr);
227           ierr = DMSetLabelValue(dm, "marker", cone[0], markerLeft);CHKERRQ(ierr);
228           if (ey == edges[1]-1) {
229             ierr = DMSetLabelValue(dm, "marker", cone[1], markerLeft);CHKERRQ(ierr);
230             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft);CHKERRQ(ierr);
231           }
232         }
233       }
234     }
235     for (vy = 0; vy <= edges[1]; vy++) {
236       for (ex = 0; ex < edges[0]; ex++) {
237         PetscInt edge   = vy*edges[0]     + ex;
238         PetscInt vertex = vy*(edges[0]+1) + ex + numEdges;
239         PetscInt cone[2];
240 
241         cone[0] = vertex; cone[1] = vertex+1;
242         ierr    = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
243         if (vy == edges[1]) {
244           ierr = DMSetLabelValue(dm, "marker", edge,    markerTop);CHKERRQ(ierr);
245           ierr = DMSetLabelValue(dm, "marker", cone[0], markerTop);CHKERRQ(ierr);
246           if (ex == edges[0]-1) {
247             ierr = DMSetLabelValue(dm, "marker", cone[1], markerTop);CHKERRQ(ierr);
248             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerTop);CHKERRQ(ierr);
249           }
250         } else if (vy == 0) {
251           ierr = DMSetLabelValue(dm, "marker", edge,    markerBottom);CHKERRQ(ierr);
252           ierr = DMSetLabelValue(dm, "marker", cone[0], markerBottom);CHKERRQ(ierr);
253           if (ex == edges[0]-1) {
254             ierr = DMSetLabelValue(dm, "marker", cone[1], markerBottom);CHKERRQ(ierr);
255             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom);CHKERRQ(ierr);
256           }
257         }
258       }
259     }
260   }
261   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
262   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
263   /* Build coordinates */
264   ierr = DMSetCoordinateDim(dm, 2);CHKERRQ(ierr);
265   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
266   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
267   ierr = PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices);CHKERRQ(ierr);
268   ierr = PetscSectionSetFieldComponents(coordSection, 0, 2);CHKERRQ(ierr);
269   for (v = numEdges; v < numEdges+numVertices; ++v) {
270     ierr = PetscSectionSetDof(coordSection, v, 2);CHKERRQ(ierr);
271     ierr = PetscSectionSetFieldDof(coordSection, v, 0, 2);CHKERRQ(ierr);
272   }
273   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
274   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
275   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
276   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
277   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
278   ierr = VecSetBlockSize(coordinates, 2);CHKERRQ(ierr);
279   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
280   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
281   for (vy = 0; vy <= edges[1]; ++vy) {
282     for (vx = 0; vx <= edges[0]; ++vx) {
283       coords[(vy*(edges[0]+1)+vx)*2+0] = lower[0] + ((upper[0] - lower[0])/edges[0])*vx;
284       coords[(vy*(edges[0]+1)+vx)*2+1] = lower[1] + ((upper[1] - lower[1])/edges[1])*vy;
285     }
286   }
287   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
288   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
289   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
290   PetscFunctionReturn(0);
291 }
292 
293 /*@
294   DMPlexCreateCubeBoundary - Creates a 2D mesh that is the boundary of a cubic lattice.
295 
296   Collective
297 
298   Input Parameters:
299 + comm  - The communicator for the DM object
300 . lower - The lower left front corner coordinates
301 . upper - The upper right back corner coordinates
302 - faces - The number of faces in each direction (the same as the number of cells)
303 
304   Output Parameter:
305 . dm  - The DM object
306 
307   Level: beginner
308 
309 .seealso: DMPlexCreateBoxMesh(), DMPlexCreateSquareBoundary(), DMSetType(), DMCreate()
310 @*/
311 PetscErrorCode DMPlexCreateCubeBoundary(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
312 {
313   PetscInt       vertices[3], numVertices;
314   PetscInt       numFaces    = 2*faces[0]*faces[1] + 2*faces[1]*faces[2] + 2*faces[0]*faces[2];
315   Vec            coordinates;
316   PetscSection   coordSection;
317   PetscScalar    *coords;
318   PetscInt       coordSize;
319   PetscMPIInt    rank;
320   PetscInt       v, vx, vy, vz;
321   PetscInt       voffset, iface=0, cone[4];
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   if ((faces[0] < 1) || (faces[1] < 1) || (faces[2] < 1)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
326   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
327   vertices[0] = faces[0]+1; vertices[1] = faces[1]+1; vertices[2] = faces[2]+1;
328   numVertices = vertices[0]*vertices[1]*vertices[2];
329   if (!rank) {
330     PetscInt f;
331 
332     ierr = DMPlexSetChart(dm, 0, numFaces+numVertices);CHKERRQ(ierr);
333     for (f = 0; f < numFaces; ++f) {
334       ierr = DMPlexSetConeSize(dm, f, 4);CHKERRQ(ierr);
335     }
336     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
337 
338     /* Side 0 (Top) */
339     for (vy = 0; vy < faces[1]; vy++) {
340       for (vx = 0; vx < faces[0]; vx++) {
341         voffset = numFaces + vertices[0]*vertices[1]*(vertices[2]-1) + vy*vertices[0] + vx;
342         cone[0] = voffset; cone[1] = voffset+1; cone[2] = voffset+vertices[0]+1; cone[3] = voffset+vertices[0];
343         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
344         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
345         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
346         ierr    = DMSetLabelValue(dm, "marker", voffset+1, 1);CHKERRQ(ierr);
347         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+0, 1);CHKERRQ(ierr);
348         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+1, 1);CHKERRQ(ierr);
349         iface++;
350       }
351     }
352 
353     /* Side 1 (Bottom) */
354     for (vy = 0; vy < faces[1]; vy++) {
355       for (vx = 0; vx < faces[0]; vx++) {
356         voffset = numFaces + vy*(faces[0]+1) + vx;
357         cone[0] = voffset+1; cone[1] = voffset; cone[2] = voffset+vertices[0]; cone[3] = voffset+vertices[0]+1;
358         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
359         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
360         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
361         ierr    = DMSetLabelValue(dm, "marker", voffset+1, 1);CHKERRQ(ierr);
362         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+0, 1);CHKERRQ(ierr);
363         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+1, 1);CHKERRQ(ierr);
364         iface++;
365       }
366     }
367 
368     /* Side 2 (Front) */
369     for (vz = 0; vz < faces[2]; vz++) {
370       for (vx = 0; vx < faces[0]; vx++) {
371         voffset = numFaces + vz*vertices[0]*vertices[1] + vx;
372         cone[0] = voffset; cone[1] = voffset+1; cone[2] = voffset+vertices[0]*vertices[1]+1; cone[3] = voffset+vertices[0]*vertices[1];
373         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
374         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
375         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
376         ierr    = DMSetLabelValue(dm, "marker", voffset+1, 1);CHKERRQ(ierr);
377         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+0, 1);CHKERRQ(ierr);
378         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+1, 1);CHKERRQ(ierr);
379         iface++;
380       }
381     }
382 
383     /* Side 3 (Back) */
384     for (vz = 0; vz < faces[2]; vz++) {
385       for (vx = 0; vx < faces[0]; vx++) {
386         voffset = numFaces + vz*vertices[0]*vertices[1] + vertices[0]*(vertices[1]-1) + vx;
387         cone[0] = voffset+vertices[0]*vertices[1]; cone[1] = voffset+vertices[0]*vertices[1]+1;
388         cone[2] = voffset+1; cone[3] = voffset;
389         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
390         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
391         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
392         ierr    = DMSetLabelValue(dm, "marker", voffset+1, 1);CHKERRQ(ierr);
393         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+0, 1);CHKERRQ(ierr);
394         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+1, 1);CHKERRQ(ierr);
395         iface++;
396       }
397     }
398 
399     /* Side 4 (Left) */
400     for (vz = 0; vz < faces[2]; vz++) {
401       for (vy = 0; vy < faces[1]; vy++) {
402         voffset = numFaces + vz*vertices[0]*vertices[1] + vy*vertices[0];
403         cone[0] = voffset; cone[1] = voffset+vertices[0]*vertices[1];
404         cone[2] = voffset+vertices[0]*vertices[1]+vertices[0]; cone[3] = voffset+vertices[0];
405         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
406         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
407         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
408         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+0, 1);CHKERRQ(ierr);
409         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[1]+0, 1);CHKERRQ(ierr);
410         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+vertices[0], 1);CHKERRQ(ierr);
411         iface++;
412       }
413     }
414 
415     /* Side 5 (Right) */
416     for (vz = 0; vz < faces[2]; vz++) {
417       for (vy = 0; vy < faces[1]; vy++) {
418         voffset = numFaces + vz*vertices[0]*vertices[1] + vy*vertices[0] + faces[0];
419         cone[0] = voffset+vertices[0]*vertices[1]; cone[1] = voffset;
420         cone[2] = voffset+vertices[0]; cone[3] = voffset+vertices[0]*vertices[1]+vertices[0];
421         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
422         ierr    = DMSetLabelValue(dm, "marker", iface, 1);CHKERRQ(ierr);
423         ierr    = DMSetLabelValue(dm, "marker", voffset+0, 1);CHKERRQ(ierr);
424         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]+0, 1);CHKERRQ(ierr);
425         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+0, 1);CHKERRQ(ierr);
426         ierr    = DMSetLabelValue(dm, "marker", voffset+vertices[0]*vertices[1]+vertices[0], 1);CHKERRQ(ierr);
427         iface++;
428       }
429     }
430   }
431   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
432   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
433   /* Build coordinates */
434   ierr = DMSetCoordinateDim(dm, 3);CHKERRQ(ierr);
435   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
436   ierr = PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices);CHKERRQ(ierr);
437   for (v = numFaces; v < numFaces+numVertices; ++v) {
438     ierr = PetscSectionSetDof(coordSection, v, 3);CHKERRQ(ierr);
439   }
440   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
441   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
442   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
443   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
444   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
445   ierr = VecSetBlockSize(coordinates, 3);CHKERRQ(ierr);
446   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
447   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
448   for (vz = 0; vz <= faces[2]; ++vz) {
449     for (vy = 0; vy <= faces[1]; ++vy) {
450       for (vx = 0; vx <= faces[0]; ++vx) {
451         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+0] = lower[0] + ((upper[0] - lower[0])/faces[0])*vx;
452         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+1] = lower[1] + ((upper[1] - lower[1])/faces[1])*vy;
453         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+2] = lower[2] + ((upper[2] - lower[2])/faces[2])*vz;
454       }
455     }
456   }
457   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
458   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
459   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
460   PetscFunctionReturn(0);
461 }
462 
463 static PetscErrorCode DMPlexCreateLineMesh_Internal(MPI_Comm comm,PetscInt segments,PetscReal lower,PetscReal upper,DMBoundaryType bd,DM *dm)
464 {
465   PetscInt       i,fStart,fEnd,numCells = 0,numVerts = 0;
466   PetscInt       numPoints[2],*coneSize,*cones,*coneOrientations;
467   PetscScalar    *vertexCoords;
468   PetscReal      L,maxCell;
469   PetscBool      markerSeparate = PETSC_FALSE;
470   PetscInt       markerLeft  = 1, faceMarkerLeft  = 1;
471   PetscInt       markerRight = 1, faceMarkerRight = 2;
472   PetscBool      wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
473   PetscMPIInt    rank;
474   PetscErrorCode ierr;
475 
476   PetscFunctionBegin;
477   PetscValidPointer(dm,4);
478 
479   ierr = DMCreate(comm,dm);CHKERRQ(ierr);
480   ierr = DMSetType(*dm,DMPLEX);CHKERRQ(ierr);
481   ierr = DMSetDimension(*dm,1);CHKERRQ(ierr);
482   ierr = DMCreateLabel(*dm,"marker");CHKERRQ(ierr);
483   ierr = DMCreateLabel(*dm,"Face Sets");CHKERRQ(ierr);
484 
485   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
486   if (!rank) numCells = segments;
487   if (!rank) numVerts = segments + (wrap ? 0 : 1);
488 
489   numPoints[0] = numVerts ; numPoints[1] = numCells;
490   ierr = PetscMalloc4(numCells+numVerts,&coneSize,numCells*2,&cones,numCells+numVerts,&coneOrientations,numVerts,&vertexCoords);CHKERRQ(ierr);
491   ierr = PetscArrayzero(coneOrientations,numCells+numVerts);CHKERRQ(ierr);
492   for (i = 0; i < numCells; ++i) { coneSize[i] = 2; }
493   for (i = 0; i < numVerts; ++i) { coneSize[numCells+i] = 0; }
494   for (i = 0; i < numCells; ++i) { cones[2*i] = numCells + i%numVerts; cones[2*i+1] = numCells + (i+1)%numVerts; }
495   for (i = 0; i < numVerts; ++i) { vertexCoords[i] = lower + (upper-lower)*((PetscReal)i/(PetscReal)numCells); }
496   ierr = DMPlexCreateFromDAG(*dm,1,numPoints,coneSize,cones,coneOrientations,vertexCoords);CHKERRQ(ierr);
497   ierr = PetscFree4(coneSize,cones,coneOrientations,vertexCoords);CHKERRQ(ierr);
498 
499   ierr = PetscOptionsGetBool(((PetscObject)*dm)->options,((PetscObject)*dm)->prefix,"-dm_plex_separate_marker",&markerSeparate,NULL);CHKERRQ(ierr);
500   if (markerSeparate) { markerLeft = faceMarkerLeft; markerRight = faceMarkerRight;}
501   if (!wrap && !rank) {
502     ierr = DMPlexGetHeightStratum(*dm,1,&fStart,&fEnd);CHKERRQ(ierr);
503     ierr = DMSetLabelValue(*dm,"marker",fStart,markerLeft);CHKERRQ(ierr);
504     ierr = DMSetLabelValue(*dm,"marker",fEnd-1,markerRight);CHKERRQ(ierr);
505     ierr = DMSetLabelValue(*dm,"Face Sets",fStart,faceMarkerLeft);CHKERRQ(ierr);
506     ierr = DMSetLabelValue(*dm,"Face Sets",fEnd-1,faceMarkerRight);CHKERRQ(ierr);
507   }
508   if (wrap) {
509     L       = upper - lower;
510     maxCell = (PetscReal)1.1*(L/(PetscReal)PetscMax(1,segments));
511     ierr = DMSetPeriodicity(*dm,PETSC_TRUE,&maxCell,&L,&bd);CHKERRQ(ierr);
512   }
513   PetscFunctionReturn(0);
514 }
515 
516 static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm)
517 {
518   DM             boundary;
519   PetscInt       i;
520   PetscErrorCode ierr;
521 
522   PetscFunctionBegin;
523   PetscValidPointer(dm, 4);
524   for (i = 0; i < dim; ++i) if (periodicity[i] != DM_BOUNDARY_NONE) SETERRQ(comm, PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes");
525   ierr = DMCreate(comm, &boundary);CHKERRQ(ierr);
526   PetscValidLogicalCollectiveInt(boundary,dim,2);
527   ierr = DMSetType(boundary, DMPLEX);CHKERRQ(ierr);
528   ierr = DMSetDimension(boundary, dim-1);CHKERRQ(ierr);
529   ierr = DMSetCoordinateDim(boundary, dim);CHKERRQ(ierr);
530   switch (dim) {
531   case 2: ierr = DMPlexCreateSquareBoundary(boundary, lower, upper, faces);CHKERRQ(ierr);break;
532   case 3: ierr = DMPlexCreateCubeBoundary(boundary, lower, upper, faces);CHKERRQ(ierr);break;
533   default: SETERRQ1(comm, PETSC_ERR_SUP, "Dimension not supported: %D", dim);
534   }
535   ierr = DMPlexGenerate(boundary, NULL, interpolate, dm);CHKERRQ(ierr);
536   ierr = DMDestroy(&boundary);CHKERRQ(ierr);
537   PetscFunctionReturn(0);
538 }
539 
540 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
541 {
542   DMLabel        cutLabel = NULL;
543   PetscInt       markerTop      = 1, faceMarkerTop      = 1;
544   PetscInt       markerBottom   = 1, faceMarkerBottom   = 1;
545   PetscInt       markerFront    = 1, faceMarkerFront    = 1;
546   PetscInt       markerBack     = 1, faceMarkerBack     = 1;
547   PetscInt       markerRight    = 1, faceMarkerRight    = 1;
548   PetscInt       markerLeft     = 1, faceMarkerLeft     = 1;
549   PetscInt       dim;
550   PetscBool      markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
551   PetscMPIInt    rank;
552   PetscErrorCode ierr;
553 
554   PetscFunctionBegin;
555   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
556   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
557   ierr = DMCreateLabel(dm,"marker");CHKERRQ(ierr);
558   ierr = DMCreateLabel(dm,"Face Sets");CHKERRQ(ierr);
559   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL);CHKERRQ(ierr);
560   if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ||
561       bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ||
562       bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) {
563 
564     if (cutMarker) {ierr = DMCreateLabel(dm, "periodic_cut");CHKERRQ(ierr); ierr = DMGetLabel(dm, "periodic_cut", &cutLabel);CHKERRQ(ierr);}
565   }
566   switch (dim) {
567   case 2:
568     faceMarkerTop    = 3;
569     faceMarkerBottom = 1;
570     faceMarkerRight  = 2;
571     faceMarkerLeft   = 4;
572     break;
573   case 3:
574     faceMarkerBottom = 1;
575     faceMarkerTop    = 2;
576     faceMarkerFront  = 3;
577     faceMarkerBack   = 4;
578     faceMarkerRight  = 5;
579     faceMarkerLeft   = 6;
580     break;
581   default:
582     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Dimension %D not supported",dim);
583     break;
584   }
585   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL);CHKERRQ(ierr);
586   if (markerSeparate) {
587     markerBottom = faceMarkerBottom;
588     markerTop    = faceMarkerTop;
589     markerFront  = faceMarkerFront;
590     markerBack   = faceMarkerBack;
591     markerRight  = faceMarkerRight;
592     markerLeft   = faceMarkerLeft;
593   }
594   {
595     const PetscInt numXEdges    = !rank ? edges[0] : 0;
596     const PetscInt numYEdges    = !rank ? edges[1] : 0;
597     const PetscInt numZEdges    = !rank ? edges[2] : 0;
598     const PetscInt numXVertices = !rank ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0]+1) : 0;
599     const PetscInt numYVertices = !rank ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1]+1) : 0;
600     const PetscInt numZVertices = !rank ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2]+1) : 0;
601     const PetscInt numCells     = numXEdges*numYEdges*numZEdges;
602     const PetscInt numXFaces    = numYEdges*numZEdges;
603     const PetscInt numYFaces    = numXEdges*numZEdges;
604     const PetscInt numZFaces    = numXEdges*numYEdges;
605     const PetscInt numTotXFaces = numXVertices*numXFaces;
606     const PetscInt numTotYFaces = numYVertices*numYFaces;
607     const PetscInt numTotZFaces = numZVertices*numZFaces;
608     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
609     const PetscInt numTotXEdges = numXEdges*numYVertices*numZVertices;
610     const PetscInt numTotYEdges = numYEdges*numXVertices*numZVertices;
611     const PetscInt numTotZEdges = numZEdges*numXVertices*numYVertices;
612     const PetscInt numVertices  = numXVertices*numYVertices*numZVertices;
613     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
614     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
615     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
616     const PetscInt firstYFace   = firstXFace + numTotXFaces;
617     const PetscInt firstZFace   = firstYFace + numTotYFaces;
618     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
619     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
620     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
621     Vec            coordinates;
622     PetscSection   coordSection;
623     PetscScalar   *coords;
624     PetscInt       coordSize;
625     PetscInt       v, vx, vy, vz;
626     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;
627 
628     ierr = DMPlexSetChart(dm, 0, numCells+numFaces+numEdges+numVertices);CHKERRQ(ierr);
629     for (c = 0; c < numCells; c++) {
630       ierr = DMPlexSetConeSize(dm, c, 6);CHKERRQ(ierr);
631     }
632     for (f = firstXFace; f < firstXFace+numFaces; ++f) {
633       ierr = DMPlexSetConeSize(dm, f, 4);CHKERRQ(ierr);
634     }
635     for (e = firstXEdge; e < firstXEdge+numEdges; ++e) {
636       ierr = DMPlexSetConeSize(dm, e, 2);CHKERRQ(ierr);
637     }
638     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
639     /* Build cells */
640     for (fz = 0; fz < numZEdges; ++fz) {
641       for (fy = 0; fy < numYEdges; ++fy) {
642         for (fx = 0; fx < numXEdges; ++fx) {
643           PetscInt cell    = (fz*numYEdges + fy)*numXEdges + fx;
644           PetscInt faceB   = firstZFace + (fy*numXEdges+fx)*numZVertices +   fz;
645           PetscInt faceT   = firstZFace + (fy*numXEdges+fx)*numZVertices + ((fz+1)%numZVertices);
646           PetscInt faceF   = firstYFace + (fz*numXEdges+fx)*numYVertices +   fy;
647           PetscInt faceK   = firstYFace + (fz*numXEdges+fx)*numYVertices + ((fy+1)%numYVertices);
648           PetscInt faceL   = firstXFace + (fz*numYEdges+fy)*numXVertices +   fx;
649           PetscInt faceR   = firstXFace + (fz*numYEdges+fy)*numXVertices + ((fx+1)%numXVertices);
650                             /* B,  T,  F,  K,  R,  L */
651           PetscInt ornt[6] = {-4,  0,  0, -1,  0, -4}; /* ??? */
652           PetscInt cone[6];
653 
654           /* no boundary twisting in 3D */
655           cone[0] = faceB; cone[1] = faceT; cone[2] = faceF; cone[3] = faceK; cone[4] = faceR; cone[5] = faceL;
656           ierr    = DMPlexSetCone(dm, cell, cone);CHKERRQ(ierr);
657           ierr    = DMPlexSetConeOrientation(dm, cell, ornt);CHKERRQ(ierr);
658           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
659           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
660           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
661         }
662       }
663     }
664     /* Build x faces */
665     for (fz = 0; fz < numZEdges; ++fz) {
666       for (fy = 0; fy < numYEdges; ++fy) {
667         for (fx = 0; fx < numXVertices; ++fx) {
668           PetscInt face    = firstXFace + (fz*numYEdges+fy)     *numXVertices+fx;
669           PetscInt edgeL   = firstZEdge + (fy                   *numXVertices+fx)*numZEdges + fz;
670           PetscInt edgeR   = firstZEdge + (((fy+1)%numYVertices)*numXVertices+fx)*numZEdges + fz;
671           PetscInt edgeB   = firstYEdge + (fz                   *numXVertices+fx)*numYEdges + fy;
672           PetscInt edgeT   = firstYEdge + (((fz+1)%numZVertices)*numXVertices+fx)*numYEdges + fy;
673           PetscInt ornt[4] = {0, 0, -2, -2};
674           PetscInt cone[4];
675 
676           if (dim == 3) {
677             /* markers */
678             if (bdX != DM_BOUNDARY_PERIODIC) {
679               if (fx == numXVertices-1) {
680                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight);CHKERRQ(ierr);
681                 ierr = DMSetLabelValue(dm, "marker", face, markerRight);CHKERRQ(ierr);
682               }
683               else if (fx == 0) {
684                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft);CHKERRQ(ierr);
685                 ierr = DMSetLabelValue(dm, "marker", face, markerLeft);CHKERRQ(ierr);
686               }
687             }
688           }
689           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
690           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
691           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
692         }
693       }
694     }
695     /* Build y faces */
696     for (fz = 0; fz < numZEdges; ++fz) {
697       for (fx = 0; fx < numXEdges; ++fx) {
698         for (fy = 0; fy < numYVertices; ++fy) {
699           PetscInt face    = firstYFace + (fz*numXEdges+fx)*numYVertices + fy;
700           PetscInt edgeL   = firstZEdge + (fy*numXVertices+  fx)*numZEdges + fz;
701           PetscInt edgeR   = firstZEdge + (fy*numXVertices+((fx+1)%numXVertices))*numZEdges + fz;
702           PetscInt edgeB   = firstXEdge + (fz                   *numYVertices+fy)*numXEdges + fx;
703           PetscInt edgeT   = firstXEdge + (((fz+1)%numZVertices)*numYVertices+fy)*numXEdges + fx;
704           PetscInt ornt[4] = {0, 0, -2, -2};
705           PetscInt cone[4];
706 
707           if (dim == 3) {
708             /* markers */
709             if (bdY != DM_BOUNDARY_PERIODIC) {
710               if (fy == numYVertices-1) {
711                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack);CHKERRQ(ierr);
712                 ierr = DMSetLabelValue(dm, "marker", face, markerBack);CHKERRQ(ierr);
713               }
714               else if (fy == 0) {
715                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront);CHKERRQ(ierr);
716                 ierr = DMSetLabelValue(dm, "marker", face, markerFront);CHKERRQ(ierr);
717               }
718             }
719           }
720           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
721           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
722           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
723         }
724       }
725     }
726     /* Build z faces */
727     for (fy = 0; fy < numYEdges; ++fy) {
728       for (fx = 0; fx < numXEdges; ++fx) {
729         for (fz = 0; fz < numZVertices; fz++) {
730           PetscInt face    = firstZFace + (fy*numXEdges+fx)*numZVertices + fz;
731           PetscInt edgeL   = firstYEdge + (fz*numXVertices+  fx)*numYEdges + fy;
732           PetscInt edgeR   = firstYEdge + (fz*numXVertices+((fx+1)%numXVertices))*numYEdges + fy;
733           PetscInt edgeB   = firstXEdge + (fz*numYVertices+  fy)*numXEdges + fx;
734           PetscInt edgeT   = firstXEdge + (fz*numYVertices+((fy+1)%numYVertices))*numXEdges + fx;
735           PetscInt ornt[4] = {0, 0, -2, -2};
736           PetscInt cone[4];
737 
738           if (dim == 2) {
739             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges-1) {edgeR += numYEdges-1-2*fy; ornt[1] = -2;}
740             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges-1) {edgeT += numXEdges-1-2*fx; ornt[2] =  0;}
741             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, face, 2);CHKERRQ(ierr);}
742             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, face, 2);CHKERRQ(ierr);}
743           } else {
744             /* markers */
745             if (bdZ != DM_BOUNDARY_PERIODIC) {
746               if (fz == numZVertices-1) {
747                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop);CHKERRQ(ierr);
748                 ierr = DMSetLabelValue(dm, "marker", face, markerTop);CHKERRQ(ierr);
749               }
750               else if (fz == 0) {
751                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom);CHKERRQ(ierr);
752                 ierr = DMSetLabelValue(dm, "marker", face, markerBottom);CHKERRQ(ierr);
753               }
754             }
755           }
756           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
757           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
758           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
759         }
760       }
761     }
762     /* Build Z edges*/
763     for (vy = 0; vy < numYVertices; vy++) {
764       for (vx = 0; vx < numXVertices; vx++) {
765         for (ez = 0; ez < numZEdges; ez++) {
766           const PetscInt edge    = firstZEdge  + (vy*numXVertices+vx)*numZEdges + ez;
767           const PetscInt vertexB = firstVertex + (ez                   *numYVertices+vy)*numXVertices + vx;
768           const PetscInt vertexT = firstVertex + (((ez+1)%numZVertices)*numYVertices+vy)*numXVertices + vx;
769           PetscInt       cone[2];
770 
771           if (dim == 3) {
772             if (bdX != DM_BOUNDARY_PERIODIC) {
773               if (vx == numXVertices-1) {
774                 ierr = DMSetLabelValue(dm, "marker", edge, markerRight);CHKERRQ(ierr);
775               }
776               else if (vx == 0) {
777                 ierr = DMSetLabelValue(dm, "marker", edge, markerLeft);CHKERRQ(ierr);
778               }
779             }
780             if (bdY != DM_BOUNDARY_PERIODIC) {
781               if (vy == numYVertices-1) {
782                 ierr = DMSetLabelValue(dm, "marker", edge, markerBack);CHKERRQ(ierr);
783               }
784               else if (vy == 0) {
785                 ierr = DMSetLabelValue(dm, "marker", edge, markerFront);CHKERRQ(ierr);
786               }
787             }
788           }
789           cone[0] = vertexB; cone[1] = vertexT;
790           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
791         }
792       }
793     }
794     /* Build Y edges*/
795     for (vz = 0; vz < numZVertices; vz++) {
796       for (vx = 0; vx < numXVertices; vx++) {
797         for (ey = 0; ey < numYEdges; ey++) {
798           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges-1) ? (numXVertices-vx-1) : (vz*numYVertices+((ey+1)%numYVertices))*numXVertices + vx;
799           const PetscInt edge    = firstYEdge  + (vz*numXVertices+vx)*numYEdges + ey;
800           const PetscInt vertexF = firstVertex + (vz*numYVertices+ey)*numXVertices + vx;
801           const PetscInt vertexK = firstVertex + nextv;
802           PetscInt       cone[2];
803 
804           cone[0] = vertexF; cone[1] = vertexK;
805           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
806           if (dim == 2) {
807             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
808               if (vx == numXVertices-1) {
809                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight);CHKERRQ(ierr);
810                 ierr = DMSetLabelValue(dm, "marker", edge,    markerRight);CHKERRQ(ierr);
811                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerRight);CHKERRQ(ierr);
812                 if (ey == numYEdges-1) {
813                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerRight);CHKERRQ(ierr);
814                 }
815               } else if (vx == 0) {
816                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft);CHKERRQ(ierr);
817                 ierr = DMSetLabelValue(dm, "marker", edge,    markerLeft);CHKERRQ(ierr);
818                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerLeft);CHKERRQ(ierr);
819                 if (ey == numYEdges-1) {
820                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerLeft);CHKERRQ(ierr);
821                 }
822               }
823             } else {
824               if (vx == 0 && cutLabel) {
825                 ierr = DMLabelSetValue(cutLabel, edge,    1);CHKERRQ(ierr);
826                 ierr = DMLabelSetValue(cutLabel, cone[0], 1);CHKERRQ(ierr);
827                 if (ey == numYEdges-1) {
828                   ierr = DMLabelSetValue(cutLabel, cone[1], 1);CHKERRQ(ierr);
829                 }
830               }
831             }
832           } else {
833             if (bdX != DM_BOUNDARY_PERIODIC) {
834               if (vx == numXVertices-1) {
835                 ierr = DMSetLabelValue(dm, "marker", edge, markerRight);CHKERRQ(ierr);
836               } else if (vx == 0) {
837                 ierr = DMSetLabelValue(dm, "marker", edge, markerLeft);CHKERRQ(ierr);
838               }
839             }
840             if (bdZ != DM_BOUNDARY_PERIODIC) {
841               if (vz == numZVertices-1) {
842                 ierr = DMSetLabelValue(dm, "marker", edge, markerTop);CHKERRQ(ierr);
843               } else if (vz == 0) {
844                 ierr = DMSetLabelValue(dm, "marker", edge, markerBottom);CHKERRQ(ierr);
845               }
846             }
847           }
848         }
849       }
850     }
851     /* Build X edges*/
852     for (vz = 0; vz < numZVertices; vz++) {
853       for (vy = 0; vy < numYVertices; vy++) {
854         for (ex = 0; ex < numXEdges; ex++) {
855           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges-1) ? (numYVertices-vy-1)*numXVertices : (vz*numYVertices+vy)*numXVertices + (ex+1)%numXVertices;
856           const PetscInt edge    = firstXEdge  + (vz*numYVertices+vy)*numXEdges + ex;
857           const PetscInt vertexL = firstVertex + (vz*numYVertices+vy)*numXVertices + ex;
858           const PetscInt vertexR = firstVertex + nextv;
859           PetscInt       cone[2];
860 
861           cone[0] = vertexL; cone[1] = vertexR;
862           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
863           if (dim == 2) {
864             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
865               if (vy == numYVertices-1) {
866                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop);CHKERRQ(ierr);
867                 ierr = DMSetLabelValue(dm, "marker", edge,    markerTop);CHKERRQ(ierr);
868                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerTop);CHKERRQ(ierr);
869                 if (ex == numXEdges-1) {
870                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerTop);CHKERRQ(ierr);
871                 }
872               } else if (vy == 0) {
873                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom);CHKERRQ(ierr);
874                 ierr = DMSetLabelValue(dm, "marker", edge,    markerBottom);CHKERRQ(ierr);
875                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerBottom);CHKERRQ(ierr);
876                 if (ex == numXEdges-1) {
877                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerBottom);CHKERRQ(ierr);
878                 }
879               }
880             } else {
881               if (vy == 0 && cutLabel) {
882                 ierr = DMLabelSetValue(cutLabel, edge,    1);CHKERRQ(ierr);
883                 ierr = DMLabelSetValue(cutLabel, cone[0], 1);CHKERRQ(ierr);
884                 if (ex == numXEdges-1) {
885                   ierr = DMLabelSetValue(cutLabel, cone[1], 1);CHKERRQ(ierr);
886                 }
887               }
888             }
889           } else {
890             if (bdY != DM_BOUNDARY_PERIODIC) {
891               if (vy == numYVertices-1) {
892                 ierr = DMSetLabelValue(dm, "marker", edge, markerBack);CHKERRQ(ierr);
893               }
894               else if (vy == 0) {
895                 ierr = DMSetLabelValue(dm, "marker", edge, markerFront);CHKERRQ(ierr);
896               }
897             }
898             if (bdZ != DM_BOUNDARY_PERIODIC) {
899               if (vz == numZVertices-1) {
900                 ierr = DMSetLabelValue(dm, "marker", edge, markerTop);CHKERRQ(ierr);
901               }
902               else if (vz == 0) {
903                 ierr = DMSetLabelValue(dm, "marker", edge, markerBottom);CHKERRQ(ierr);
904               }
905             }
906           }
907         }
908       }
909     }
910     ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
911     ierr = DMPlexStratify(dm);CHKERRQ(ierr);
912     /* Build coordinates */
913     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
914     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
915     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
916     ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numVertices);CHKERRQ(ierr);
917     for (v = firstVertex; v < firstVertex+numVertices; ++v) {
918       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
919       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
920     }
921     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
922     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
923     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
924     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
925     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
926     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
927     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
928     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
929     for (vz = 0; vz < numZVertices; ++vz) {
930       for (vy = 0; vy < numYVertices; ++vy) {
931         for (vx = 0; vx < numXVertices; ++vx) {
932           coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+0] = lower[0] + ((upper[0] - lower[0])/numXEdges)*vx;
933           coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+1] = lower[1] + ((upper[1] - lower[1])/numYEdges)*vy;
934           if (dim == 3) {
935             coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+2] = lower[2] + ((upper[2] - lower[2])/numZEdges)*vz;
936           }
937         }
938       }
939     }
940     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
941     ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
942     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
943   }
944   PetscFunctionReturn(0);
945 }
946 
947 static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm)
948 {
949   PetscInt       i;
950   PetscErrorCode ierr;
951 
952   PetscFunctionBegin;
953   PetscValidPointer(dm, 7);
954   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
955   PetscValidLogicalCollectiveInt(*dm,dim,2);
956   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
957   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
958   switch (dim) {
959   case 2: {ierr = DMPlexCreateCubeMesh_Internal(*dm, lower, upper, faces, periodicity[0], periodicity[1], DM_BOUNDARY_NONE);CHKERRQ(ierr);break;}
960   case 3: {ierr = DMPlexCreateCubeMesh_Internal(*dm, lower, upper, faces, periodicity[0], periodicity[1], periodicity[2]);CHKERRQ(ierr);break;}
961   default: SETERRQ1(comm, PETSC_ERR_SUP, "Dimension not supported: %D", dim);
962   }
963   if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST ||
964       periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST ||
965       (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) {
966     PetscReal L[3];
967     PetscReal maxCell[3];
968 
969     for (i = 0; i < dim; i++) {
970       L[i]       = upper[i] - lower[i];
971       maxCell[i] = 1.1 * (L[i] / PetscMax(1,faces[i]));
972     }
973     ierr = DMSetPeriodicity(*dm,PETSC_TRUE,maxCell,L,periodicity);CHKERRQ(ierr);
974   }
975   if (!interpolate) {
976     DM udm;
977 
978     ierr = DMPlexUninterpolate(*dm, &udm);CHKERRQ(ierr);
979     ierr = DMPlexCopyCoordinates(*dm, udm);CHKERRQ(ierr);
980     ierr = DMDestroy(dm);CHKERRQ(ierr);
981     *dm  = udm;
982   }
983   PetscFunctionReturn(0);
984 }
985 
986 /*@C
987   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).
988 
989   Collective
990 
991   Input Parameters:
992 + comm        - The communicator for the DM object
993 . dim         - The spatial dimension
994 . simplex     - PETSC_TRUE for simplices, PETSC_FALSE for tensor cells
995 . faces       - Number of faces per dimension, or NULL for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
996 . lower       - The lower left corner, or NULL for (0, 0, 0)
997 . upper       - The upper right corner, or NULL for (1, 1, 1)
998 . periodicity - The boundary type for the X,Y,Z direction, or NULL for DM_BOUNDARY_NONE
999 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1000 
1001   Output Parameter:
1002 . dm  - The DM object
1003 
1004   Options Database Keys:
1005   These options override the hard-wired input values.
1006 + -dm_plex_box_dim <dim>       - Set the topological dimension
1007 . -dm_plex_box_simplex <bool>  - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
1008 . -dm_plex_box_lower <x,y,z>   - Specify lower-left-bottom coordinates for the box
1009 . -dm_plex_box_upper <x,y,z>   - Specify upper-right-top coordinates for the box
1010 - -dm_plex_box_faces <m,n,p>   - Number of faces in each linear direction
1011 
1012 
1013   Notes:
1014   The options database keys above take lists of length d in d dimensions.
1015 
1016   Here is the numbering returned for 2 faces in each direction for tensor cells:
1017 $ 10---17---11---18----12
1018 $  |         |         |
1019 $  |         |         |
1020 $ 20    2   22    3    24
1021 $  |         |         |
1022 $  |         |         |
1023 $  7---15----8---16----9
1024 $  |         |         |
1025 $  |         |         |
1026 $ 19    0   21    1   23
1027 $  |         |         |
1028 $  |         |         |
1029 $  4---13----5---14----6
1030 
1031 and for simplicial cells
1032 
1033 $ 14----8---15----9----16
1034 $  |\     5  |\      7 |
1035 $  | \       | \       |
1036 $ 13   2    14    3    15
1037 $  | 4   \   | 6   \   |
1038 $  |       \ |       \ |
1039 $ 11----6---12----7----13
1040 $  |\        |\        |
1041 $  | \    1  | \     3 |
1042 $ 10   0    11    1    12
1043 $  | 0   \   | 2   \   |
1044 $  |       \ |       \ |
1045 $  8----4----9----5----10
1046 
1047   Level: beginner
1048 
1049 .seealso: DMPlexCreateFromFile(), DMPlexCreateHexCylinderMesh(), DMSetType(), DMCreate()
1050 @*/
1051 PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, DM *dm)
1052 {
1053   PetscInt       fac[3] = {0, 0, 0};
1054   PetscReal      low[3] = {0, 0, 0};
1055   PetscReal      upp[3] = {1, 1, 1};
1056   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1057   PetscInt       i, n;
1058   PetscBool      flg;
1059   PetscErrorCode ierr;
1060 
1061   PetscFunctionBegin;
1062   ierr = PetscOptionsGetInt(NULL, NULL, "-dm_plex_box_dim", &dim, &flg);CHKERRQ(ierr);
1063   if ((dim < 0) || (dim > 3)) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D should be in [1, 3]", dim);
1064   ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_box_simplex", &simplex, &flg);CHKERRQ(ierr);
1065   n    = 3;
1066   ierr = PetscOptionsGetIntArray(NULL, NULL, "-dm_plex_box_faces", fac, &n, &flg);CHKERRQ(ierr);
1067   for (i = 0; i < dim; ++i) fac[i] = faces ? faces[i] : (flg && i < n ? fac[i] : (dim == 1 ? 1 : 4-dim));
1068   if (lower) for (i = 0; i < dim; ++i) low[i] = lower[i];
1069   if (upper) for (i = 0; i < dim; ++i) upp[i] = upper[i];
1070   if (periodicity) for (i = 0; i < dim; ++i) bdt[i] = periodicity[i];
1071   /* Allow bounds to be specified from the command line */
1072   n    = 3;
1073   ierr = PetscOptionsGetRealArray(NULL, NULL, "-dm_plex_box_lower", low, &n, &flg);CHKERRQ(ierr);
1074   if (flg && (n != dim)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Lower box point had %D values, should have been %D", n, dim);
1075   n    = 3;
1076   ierr = PetscOptionsGetRealArray(NULL, NULL, "-dm_plex_box_upper", upp, &n, &flg);CHKERRQ(ierr);
1077   if (flg && (n != dim)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Upper box point had %D values, should have been %D", n, dim);
1078 
1079   if (dim == 1)      {ierr = DMPlexCreateLineMesh_Internal(comm, fac[0], low[0], upp[0], bdt[0], dm);CHKERRQ(ierr);}
1080   else if (simplex)  {ierr = DMPlexCreateBoxMesh_Simplex_Internal(comm, dim, fac, low, upp, bdt, interpolate, dm);CHKERRQ(ierr);}
1081   else               {ierr = DMPlexCreateBoxMesh_Tensor_Internal(comm, dim, fac, low, upp, bdt, interpolate, dm);CHKERRQ(ierr);}
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 /*@
1086   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tesselating the (x,y) plane and extruding in the third direction using wedge cells.
1087 
1088   Collective
1089 
1090   Input Parameters:
1091 + comm        - The communicator for the DM object
1092 . faces       - Number of faces per dimension, or NULL for (1, 1, 1)
1093 . lower       - The lower left corner, or NULL for (0, 0, 0)
1094 . upper       - The upper right corner, or NULL for (1, 1, 1)
1095 . periodicity - The boundary type for the X,Y,Z direction, or NULL for DM_BOUNDARY_NONE
1096 . orderHeight - If PETSC_TRUE, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1097 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1098 
1099   Output Parameter:
1100 . dm  - The DM object
1101 
1102   Level: beginner
1103 
1104 .seealso: DMPlexCreateHexCylinderMesh(), DMPlexCreateWedgeCylinderMesh(), DMPlexExtrude(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1105 @*/
1106 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
1107 {
1108   DM             bdm, botdm;
1109   PetscInt       i;
1110   PetscInt       fac[3] = {0, 0, 0};
1111   PetscReal      low[3] = {0, 0, 0};
1112   PetscReal      upp[3] = {1, 1, 1};
1113   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1114   PetscErrorCode ierr;
1115 
1116   PetscFunctionBegin;
1117   for (i = 0; i < 3; ++i) fac[i] = faces ? (faces[i] > 0 ? faces[i] : 1) : 1;
1118   if (lower) for (i = 0; i < 3; ++i) low[i] = lower[i];
1119   if (upper) for (i = 0; i < 3; ++i) upp[i] = upper[i];
1120   if (periodicity) for (i = 0; i < 3; ++i) bdt[i] = periodicity[i];
1121   for (i = 0; i < 3; ++i) if (bdt[i] != DM_BOUNDARY_NONE) SETERRQ(comm, PETSC_ERR_SUP, "Periodicity not yet supported");
1122 
1123   ierr = DMCreate(comm, &bdm);CHKERRQ(ierr);
1124   ierr = DMSetType(bdm, DMPLEX);CHKERRQ(ierr);
1125   ierr = DMSetDimension(bdm, 1);CHKERRQ(ierr);
1126   ierr = DMSetCoordinateDim(bdm, 2);CHKERRQ(ierr);
1127   ierr = DMPlexCreateSquareBoundary(bdm, low, upp, fac);CHKERRQ(ierr);
1128   ierr = DMPlexGenerate(bdm, NULL, PETSC_FALSE, &botdm);CHKERRQ(ierr);
1129   ierr = DMDestroy(&bdm);CHKERRQ(ierr);
1130   ierr = DMPlexExtrude(botdm, fac[2], upp[2] - low[2], orderHeight, NULL, interpolate, dm);CHKERRQ(ierr);
1131   if (low[2] != 0.0) {
1132     Vec         v;
1133     PetscScalar *x;
1134     PetscInt    cDim, n;
1135 
1136     ierr = DMGetCoordinatesLocal(*dm, &v);CHKERRQ(ierr);
1137     ierr = VecGetBlockSize(v, &cDim);CHKERRQ(ierr);
1138     ierr = VecGetLocalSize(v, &n);CHKERRQ(ierr);
1139     ierr = VecGetArray(v, &x);CHKERRQ(ierr);
1140     x   += cDim;
1141     for (i=0; i<n; i+=cDim) x[i] += low[2];
1142     ierr = VecRestoreArray(v,&x);CHKERRQ(ierr);
1143     ierr = DMSetCoordinatesLocal(*dm, v);CHKERRQ(ierr);
1144   }
1145   ierr = DMDestroy(&botdm);CHKERRQ(ierr);
1146   PetscFunctionReturn(0);
1147 }
1148 
1149 /*@C
1150   DMPlexExtrude - Creates a (d+1)-D mesh by extruding a d-D mesh in the normal direction using prismatic cells.
1151 
1152   Collective on idm
1153 
1154   Input Parameters:
1155 + idm         - The mesh to be extruded
1156 . layers      - The number of layers, or PETSC_DETERMINE to use the default
1157 . height      - The height of the extruded layer, or PETSC_DETERMINE to use the default
1158 . orderHeight - If PETSC_TRUE, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1159 . extNormal   - The normal direction in which the mesh should be extruded, or NULL to extrude using the surface normal
1160 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1161 
1162   Output Parameter:
1163 . dm  - The DM object
1164 
1165   Notes:
1166   The mesh created has prismatic cells, and the vertex ordering in the cone of the cell is that of the tensor prismatic cells. Not currently supported in Fortran.
1167 
1168   Options Database Keys:
1169 +   -dm_plex_extrude_layers <k> - Sets the nubmer of layers k
1170 .   -dm_plex_extrude_height <h> - Sets the height h of each layer
1171 .   -dm_plex_extrude_order_height - If true, order cells by height first
1172 -   -dm_plex_extrude_normal <n0,...,nd> - Sets the normal vector along which to extrude
1173 
1174   Level: advanced
1175 
1176 .seealso: DMPlexCreateWedgeCylinderMesh(), DMPlexCreateWedgeBoxMesh(), DMSetType(), DMCreate()
1177 @*/
1178 PetscErrorCode DMPlexExtrude(DM idm, PetscInt layers, PetscReal height, PetscBool orderHeight, const PetscReal extNormal[], PetscBool interpolate, DM* dm)
1179 {
1180   PetscScalar       *coordsB;
1181   const PetscScalar *coordsA;
1182   PetscReal         *normals = NULL;
1183   PetscReal         clNormal[3];
1184   Vec               coordinatesA, coordinatesB;
1185   PetscSection      coordSectionA, coordSectionB;
1186   PetscInt          dim, cDim, cDimB, c, l, v, coordSize, *newCone;
1187   PetscInt          cStart, cEnd, vStart, vEnd, cellV, numCells, numVertices;
1188   const char       *prefix;
1189   PetscBool         haveCLNormal;
1190   PetscErrorCode    ierr;
1191 
1192   PetscFunctionBegin;
1193   PetscValidHeaderSpecific(idm, DM_CLASSID, 1);
1194   PetscValidLogicalCollectiveInt(idm, layers, 2);
1195   PetscValidLogicalCollectiveReal(idm, height, 3);
1196   PetscValidLogicalCollectiveBool(idm, interpolate, 4);
1197   ierr = DMGetDimension(idm, &dim);CHKERRQ(ierr);
1198   ierr = DMGetCoordinateDim(idm, &cDim);CHKERRQ(ierr);
1199   cDimB = cDim == dim ? cDim+1 : cDim;
1200   if (dim < 1 || dim > 3) SETERRQ1(PetscObjectComm((PetscObject)idm), PETSC_ERR_SUP, "Support for dimension %D not coded", dim);
1201 
1202   ierr = PetscObjectGetOptionsPrefix((PetscObject) idm, &prefix);CHKERRQ(ierr);
1203   if (layers < 0) layers = 1;
1204   ierr = PetscOptionsGetInt(NULL, prefix, "-dm_plex_extrude_layers", &layers, NULL);CHKERRQ(ierr);
1205   if (layers <= 0) SETERRQ1(PetscObjectComm((PetscObject) idm), PETSC_ERR_ARG_OUTOFRANGE, "Number of layers %D must be positive", layers);
1206   if (height < 0.) height = 1.;
1207   ierr = PetscOptionsGetReal(NULL, prefix, "-dm_plex_extrude_height", &height, NULL);CHKERRQ(ierr);
1208   if (height <= 0.) SETERRQ1(PetscObjectComm((PetscObject) idm), PETSC_ERR_ARG_OUTOFRANGE, "Height of layers %g must be positive", (double) height);
1209   ierr = PetscOptionsGetBool(NULL, prefix, "-dm_plex_extrude_order_height", &orderHeight, NULL);CHKERRQ(ierr);
1210   c = 3;
1211   ierr = PetscOptionsGetRealArray(NULL, prefix, "-dm_plex_extrude_normal", clNormal, &c, &haveCLNormal);CHKERRQ(ierr);
1212   if (haveCLNormal && c != cDimB) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_ARG_SIZ, "Input normal has size %D != %D extruded coordinate dimension", c, cDimB);
1213 
1214   ierr = DMPlexGetHeightStratum(idm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1215   ierr = DMPlexGetDepthStratum(idm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1216   numCells = (cEnd - cStart)*layers;
1217   numVertices = (vEnd - vStart)*(layers+1);
1218   ierr = DMCreate(PetscObjectComm((PetscObject)idm), dm);CHKERRQ(ierr);
1219   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1220   ierr = DMSetDimension(*dm, dim+1);CHKERRQ(ierr);
1221   ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1222   /* Must create the celltype label here so that we do not automatically try to compute the types */
1223   ierr = DMCreateLabel(*dm, "celltype");CHKERRQ(ierr);
1224   for (c = cStart, cellV = 0; c < cEnd; ++c) {
1225     DMPolytopeType ct, nct;
1226     PetscInt      *closure = NULL;
1227     PetscInt       closureSize, numCorners = 0;
1228 
1229     ierr = DMPlexGetCellType(idm, c, &ct);CHKERRQ(ierr);
1230     switch (ct) {
1231       case DM_POLYTOPE_SEGMENT:       nct = DM_POLYTOPE_SEG_PRISM_TENSOR;break;
1232       case DM_POLYTOPE_TRIANGLE:      nct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
1233       case DM_POLYTOPE_QUADRILATERAL: nct = DM_POLYTOPE_QUAD_PRISM_TENSOR;break;
1234       default: nct = DM_POLYTOPE_UNKNOWN;
1235     }
1236     ierr = DMPlexGetTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1237     for (v = 0; v < closureSize*2; v += 2) if ((closure[v] >= vStart) && (closure[v] < vEnd)) numCorners++;
1238     ierr = DMPlexRestoreTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1239     for (l = 0; l < layers; ++l) {
1240       const PetscInt cell = orderHeight ? layers*(c - cStart) + l : l*(cEnd - cStart) + c - cStart;
1241 
1242       ierr = DMPlexSetConeSize(*dm, cell, 2*numCorners);CHKERRQ(ierr);
1243       ierr = DMPlexSetCellType(*dm, cell, nct);CHKERRQ(ierr);
1244     }
1245     cellV = PetscMax(numCorners,cellV);
1246   }
1247   ierr = DMSetUp(*dm);CHKERRQ(ierr);
1248 
1249   if (dim != cDim && !(extNormal || haveCLNormal)) {ierr = PetscCalloc1(cDim*(vEnd - vStart), &normals);CHKERRQ(ierr);}
1250   ierr = PetscMalloc1(3*cellV,&newCone);CHKERRQ(ierr);
1251   for (c = cStart; c < cEnd; ++c) {
1252     PetscInt *closure = NULL;
1253     PetscInt closureSize, numCorners = 0, l;
1254     PetscReal normal[3] = {0, 0, 0};
1255 
1256     if (normals) {ierr = DMPlexComputeCellGeometryFVM(idm, c, NULL, NULL, normal);CHKERRQ(ierr);}
1257     ierr = DMPlexGetTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1258     for (v = 0; v < closureSize*2; v += 2) {
1259       if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
1260         PetscInt d;
1261 
1262         newCone[numCorners++] = closure[v] - vStart;
1263         if (normals) {for (d = 0; d < cDim; ++d) normals[cDim*(closure[v]-vStart)+d] += normal[d];}
1264       }
1265     }
1266     ierr = DMPlexRestoreTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1267     for (l = 0; l < layers; ++l) {
1268       PetscInt i;
1269 
1270       for (i = 0; i < numCorners; ++i) {
1271         newCone[  numCorners + i] = orderHeight ? (layers+1)*newCone[i] + l     + numCells :     l*(vEnd - vStart) + newCone[i] + numCells;
1272         newCone[2*numCorners + i] = orderHeight ? (layers+1)*newCone[i] + l + 1 + numCells : (l+1)*(vEnd - vStart) + newCone[i] + numCells;
1273       }
1274       ierr = DMPlexSetCone(*dm, orderHeight ? layers*(c - cStart) + l : l*(cEnd - cStart) + c - cStart, newCone + numCorners);CHKERRQ(ierr);
1275     }
1276   }
1277   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1278   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1279   ierr = PetscFree(newCone);CHKERRQ(ierr);
1280 
1281   ierr = DMGetCoordinateSection(*dm, &coordSectionB);CHKERRQ(ierr);
1282   ierr = PetscSectionSetNumFields(coordSectionB, 1);CHKERRQ(ierr);
1283   ierr = PetscSectionSetFieldComponents(coordSectionB, 0, cDimB);CHKERRQ(ierr);
1284   ierr = PetscSectionSetChart(coordSectionB, numCells, numCells+numVertices);CHKERRQ(ierr);
1285   for (v = numCells; v < numCells+numVertices; ++v) {
1286     ierr = PetscSectionSetDof(coordSectionB, v, cDimB);CHKERRQ(ierr);
1287     ierr = PetscSectionSetFieldDof(coordSectionB, v, 0, cDimB);CHKERRQ(ierr);
1288     ierr = DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);
1289   }
1290   ierr = PetscSectionSetUp(coordSectionB);CHKERRQ(ierr);
1291   ierr = PetscSectionGetStorageSize(coordSectionB, &coordSize);CHKERRQ(ierr);
1292   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesB);CHKERRQ(ierr);
1293   ierr = PetscObjectSetName((PetscObject) coordinatesB, "coordinates");CHKERRQ(ierr);
1294   ierr = VecSetSizes(coordinatesB, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1295   ierr = VecSetBlockSize(coordinatesB, cDimB);CHKERRQ(ierr);
1296   ierr = VecSetType(coordinatesB,VECSTANDARD);CHKERRQ(ierr);
1297 
1298   ierr = DMGetCoordinateSection(idm, &coordSectionA);CHKERRQ(ierr);
1299   ierr = DMGetCoordinatesLocal(idm, &coordinatesA);CHKERRQ(ierr);
1300   ierr = VecGetArray(coordinatesB, &coordsB);CHKERRQ(ierr);
1301   ierr = VecGetArrayRead(coordinatesA, &coordsA);CHKERRQ(ierr);
1302   for (v = vStart; v < vEnd; ++v) {
1303     const PetscScalar *cptr;
1304     PetscReal         ones2[2] = { 0., 1.}, ones3[3] = { 0., 0., 1.};
1305     PetscReal         normal[3];
1306     PetscReal         norm, h = height/layers;
1307     PetscInt          offA, d, cDimA = cDim;
1308 
1309     if (normals)           {for (d = 0; d < cDimB; ++d) normal[d] = normals[cDimB*(v - vStart)+d];}
1310     else if (haveCLNormal) {for (d = 0; d < cDimB; ++d) normal[d] = clNormal[d];}
1311     else if (extNormal)    {for (d = 0; d < cDimB; ++d) normal[d] = extNormal[d];}
1312     else if (cDimB == 2)   {for (d = 0; d < cDimB; ++d) normal[d] = ones2[d];}
1313     else if (cDimB == 3)   {for (d = 0; d < cDimB; ++d) normal[d] = ones3[d];}
1314     else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to determine normal for extrusion");
1315     for (d = 0, norm = 0.0; d < cDimB; ++d) norm += normal[d]*normal[d];
1316     for (d = 0; d < cDimB; ++d) normal[d] *= 1./PetscSqrtReal(norm);
1317 
1318     ierr = PetscSectionGetOffset(coordSectionA, v, &offA);CHKERRQ(ierr);
1319     cptr = coordsA + offA;
1320     for (l = 0; l < layers+1; ++l) {
1321       PetscInt offB, d, newV;
1322 
1323       newV = orderHeight ? (layers+1)*(v -vStart) + l + numCells : (vEnd -vStart)*l + (v -vStart) + numCells;
1324       ierr = PetscSectionGetOffset(coordSectionB, newV, &offB);CHKERRQ(ierr);
1325       for (d = 0; d < cDimA; ++d) { coordsB[offB+d]  = cptr[d]; }
1326       for (d = 0; d < cDimB; ++d) { coordsB[offB+d] += l ? normal[d]*h : 0.0; }
1327       cptr    = coordsB + offB;
1328       cDimA   = cDimB;
1329     }
1330   }
1331   ierr = VecRestoreArrayRead(coordinatesA, &coordsA);CHKERRQ(ierr);
1332   ierr = VecRestoreArray(coordinatesB, &coordsB);CHKERRQ(ierr);
1333   ierr = DMSetCoordinatesLocal(*dm, coordinatesB);CHKERRQ(ierr);
1334   ierr = VecDestroy(&coordinatesB);CHKERRQ(ierr);
1335   ierr = PetscFree(normals);CHKERRQ(ierr);
1336   if (interpolate) {
1337     DM idm;
1338 
1339     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1340     ierr = DMPlexCopyCoordinates(*dm, idm);CHKERRQ(ierr);
1341     ierr = DMDestroy(dm);CHKERRQ(ierr);
1342     *dm  = idm;
1343   }
1344   PetscFunctionReturn(0);
1345 }
1346 
1347 /*@C
1348   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all DM options in the database.
1349 
1350   Logically Collective on dm
1351 
1352   Input Parameters:
1353 + dm - the DM context
1354 - prefix - the prefix to prepend to all option names
1355 
1356   Notes:
1357   A hyphen (-) must NOT be given at the beginning of the prefix name.
1358   The first character of all runtime options is AUTOMATICALLY the hyphen.
1359 
1360   Level: advanced
1361 
1362 .seealso: SNESSetFromOptions()
1363 @*/
1364 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1365 {
1366   DM_Plex       *mesh = (DM_Plex *) dm->data;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscObjectSetOptionsPrefix((PetscObject) dm, prefix);CHKERRQ(ierr);
1372   ierr = PetscObjectSetOptionsPrefix((PetscObject) mesh->partitioner, prefix);CHKERRQ(ierr);
1373   PetscFunctionReturn(0);
1374 }
1375 
1376 /*@
1377   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
1378 
1379   Collective
1380 
1381   Input Parameters:
1382 + comm      - The communicator for the DM object
1383 . numRefine - The number of regular refinements to the basic 5 cell structure
1384 - periodicZ - The boundary type for the Z direction
1385 
1386   Output Parameter:
1387 . dm  - The DM object
1388 
1389   Note: Here is the output numbering looking from the bottom of the cylinder:
1390 $       17-----14
1391 $        |     |
1392 $        |  2  |
1393 $        |     |
1394 $ 17-----8-----7-----14
1395 $  |     |     |     |
1396 $  |  3  |  0  |  1  |
1397 $  |     |     |     |
1398 $ 19-----5-----6-----13
1399 $        |     |
1400 $        |  4  |
1401 $        |     |
1402 $       19-----13
1403 $
1404 $ and up through the top
1405 $
1406 $       18-----16
1407 $        |     |
1408 $        |  2  |
1409 $        |     |
1410 $ 18----10----11-----16
1411 $  |     |     |     |
1412 $  |  3  |  0  |  1  |
1413 $  |     |     |     |
1414 $ 20-----9----12-----15
1415 $        |     |
1416 $        |  4  |
1417 $        |     |
1418 $       20-----15
1419 
1420   Level: beginner
1421 
1422 .seealso: DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1423 @*/
1424 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, PetscInt numRefine, DMBoundaryType periodicZ, DM *dm)
1425 {
1426   const PetscInt dim = 3;
1427   PetscInt       numCells, numVertices, r;
1428   PetscMPIInt    rank;
1429   PetscErrorCode ierr;
1430 
1431   PetscFunctionBegin;
1432   PetscValidPointer(dm, 4);
1433   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1434   if (numRefine < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of refinements %D cannot be negative", numRefine);
1435   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1436   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1437   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1438   /* Create topology */
1439   {
1440     PetscInt cone[8], c;
1441 
1442     numCells    = !rank ?  5 : 0;
1443     numVertices = !rank ? 16 : 0;
1444     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1445       numCells   *= 3;
1446       numVertices = !rank ? 24 : 0;
1447     }
1448     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1449     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 8);CHKERRQ(ierr);}
1450     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1451     if (!rank) {
1452       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1453         cone[0] = 15; cone[1] = 18; cone[2] = 17; cone[3] = 16;
1454         cone[4] = 31; cone[5] = 32; cone[6] = 33; cone[7] = 34;
1455         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1456         cone[0] = 16; cone[1] = 17; cone[2] = 24; cone[3] = 23;
1457         cone[4] = 32; cone[5] = 36; cone[6] = 37; cone[7] = 33; /* 22 25 26 21 */
1458         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1459         cone[0] = 18; cone[1] = 27; cone[2] = 24; cone[3] = 17;
1460         cone[4] = 34; cone[5] = 33; cone[6] = 37; cone[7] = 38;
1461         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1462         cone[0] = 29; cone[1] = 27; cone[2] = 18; cone[3] = 15;
1463         cone[4] = 35; cone[5] = 31; cone[6] = 34; cone[7] = 38;
1464         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1465         cone[0] = 29; cone[1] = 15; cone[2] = 16; cone[3] = 23;
1466         cone[4] = 35; cone[5] = 36; cone[6] = 32; cone[7] = 31;
1467         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1468 
1469         cone[0] = 31; cone[1] = 34; cone[2] = 33; cone[3] = 32;
1470         cone[4] = 19; cone[5] = 22; cone[6] = 21; cone[7] = 20;
1471         ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1472         cone[0] = 32; cone[1] = 33; cone[2] = 37; cone[3] = 36;
1473         cone[4] = 22; cone[5] = 25; cone[6] = 26; cone[7] = 21;
1474         ierr = DMPlexSetCone(*dm, 6, cone);CHKERRQ(ierr);
1475         cone[0] = 34; cone[1] = 38; cone[2] = 37; cone[3] = 33;
1476         cone[4] = 20; cone[5] = 21; cone[6] = 26; cone[7] = 28;
1477         ierr = DMPlexSetCone(*dm, 7, cone);CHKERRQ(ierr);
1478         cone[0] = 35; cone[1] = 38; cone[2] = 34; cone[3] = 31;
1479         cone[4] = 30; cone[5] = 19; cone[6] = 20; cone[7] = 28;
1480         ierr = DMPlexSetCone(*dm, 8, cone);CHKERRQ(ierr);
1481         cone[0] = 35; cone[1] = 31; cone[2] = 32; cone[3] = 36;
1482         cone[4] = 30; cone[5] = 25; cone[6] = 22; cone[7] = 19;
1483         ierr = DMPlexSetCone(*dm, 9, cone);CHKERRQ(ierr);
1484 
1485         cone[0] = 19; cone[1] = 20; cone[2] = 21; cone[3] = 22;
1486         cone[4] = 15; cone[5] = 16; cone[6] = 17; cone[7] = 18;
1487         ierr = DMPlexSetCone(*dm, 10, cone);CHKERRQ(ierr);
1488         cone[0] = 22; cone[1] = 21; cone[2] = 26; cone[3] = 25;
1489         cone[4] = 16; cone[5] = 23; cone[6] = 24; cone[7] = 17;
1490         ierr = DMPlexSetCone(*dm, 11, cone);CHKERRQ(ierr);
1491         cone[0] = 20; cone[1] = 28; cone[2] = 26; cone[3] = 21;
1492         cone[4] = 18; cone[5] = 17; cone[6] = 24; cone[7] = 27;
1493         ierr = DMPlexSetCone(*dm, 12, cone);CHKERRQ(ierr);
1494         cone[0] = 30; cone[1] = 28; cone[2] = 20; cone[3] = 19;
1495         cone[4] = 29; cone[5] = 15; cone[6] = 18; cone[7] = 27;
1496         ierr = DMPlexSetCone(*dm, 13, cone);CHKERRQ(ierr);
1497         cone[0] = 30; cone[1] = 19; cone[2] = 22; cone[3] = 25;
1498         cone[4] = 29; cone[5] = 23; cone[6] = 16; cone[7] = 15;
1499         ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1500       } else {
1501         cone[0] =  5; cone[1] =  8; cone[2] =  7; cone[3] =  6;
1502         cone[4] =  9; cone[5] = 12; cone[6] = 11; cone[7] = 10;
1503         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1504         cone[0] =  6; cone[1] =  7; cone[2] = 14; cone[3] = 13;
1505         cone[4] = 12; cone[5] = 15; cone[6] = 16; cone[7] = 11;
1506         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1507         cone[0] =  8; cone[1] = 17; cone[2] = 14; cone[3] =  7;
1508         cone[4] = 10; cone[5] = 11; cone[6] = 16; cone[7] = 18;
1509         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1510         cone[0] = 19; cone[1] = 17; cone[2] =  8; cone[3] =  5;
1511         cone[4] = 20; cone[5] =  9; cone[6] = 10; cone[7] = 18;
1512         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1513         cone[0] = 19; cone[1] =  5; cone[2] =  6; cone[3] = 13;
1514         cone[4] = 20; cone[5] = 15; cone[6] = 12; cone[7] =  9;
1515         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1516       }
1517     }
1518     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1519     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1520   }
1521   /* Interpolate */
1522   {
1523     DM idm;
1524 
1525     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1526     ierr = DMDestroy(dm);CHKERRQ(ierr);
1527     *dm  = idm;
1528   }
1529   /* Create cube geometry */
1530   {
1531     Vec             coordinates;
1532     PetscSection    coordSection;
1533     PetscScalar    *coords;
1534     PetscInt        coordSize, v;
1535     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1536     const PetscReal ds2 = dis/2.0;
1537 
1538     /* Build coordinates */
1539     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1540     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1541     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1542     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1543     for (v = numCells; v < numCells+numVertices; ++v) {
1544       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1545       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1546     }
1547     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1548     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1549     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1550     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1551     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1552     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1553     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1554     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1555     if (!rank) {
1556       coords[0*dim+0] = -ds2; coords[0*dim+1] = -ds2; coords[0*dim+2] = 0.0;
1557       coords[1*dim+0] =  ds2; coords[1*dim+1] = -ds2; coords[1*dim+2] = 0.0;
1558       coords[2*dim+0] =  ds2; coords[2*dim+1] =  ds2; coords[2*dim+2] = 0.0;
1559       coords[3*dim+0] = -ds2; coords[3*dim+1] =  ds2; coords[3*dim+2] = 0.0;
1560       coords[4*dim+0] = -ds2; coords[4*dim+1] = -ds2; coords[4*dim+2] = 1.0;
1561       coords[5*dim+0] = -ds2; coords[5*dim+1] =  ds2; coords[5*dim+2] = 1.0;
1562       coords[6*dim+0] =  ds2; coords[6*dim+1] =  ds2; coords[6*dim+2] = 1.0;
1563       coords[7*dim+0] =  ds2; coords[7*dim+1] = -ds2; coords[7*dim+2] = 1.0;
1564       coords[ 8*dim+0] =  dis; coords[ 8*dim+1] = -dis; coords[ 8*dim+2] = 0.0;
1565       coords[ 9*dim+0] =  dis; coords[ 9*dim+1] =  dis; coords[ 9*dim+2] = 0.0;
1566       coords[10*dim+0] =  dis; coords[10*dim+1] = -dis; coords[10*dim+2] = 1.0;
1567       coords[11*dim+0] =  dis; coords[11*dim+1] =  dis; coords[11*dim+2] = 1.0;
1568       coords[12*dim+0] = -dis; coords[12*dim+1] =  dis; coords[12*dim+2] = 0.0;
1569       coords[13*dim+0] = -dis; coords[13*dim+1] =  dis; coords[13*dim+2] = 1.0;
1570       coords[14*dim+0] = -dis; coords[14*dim+1] = -dis; coords[14*dim+2] = 0.0;
1571       coords[15*dim+0] = -dis; coords[15*dim+1] = -dis; coords[15*dim+2] = 1.0;
1572       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1573         /* 15 31 19 */ coords[16*dim+0] = -ds2; coords[16*dim+1] = -ds2; coords[16*dim+2] = 0.5;
1574         /* 16 32 22 */ coords[17*dim+0] =  ds2; coords[17*dim+1] = -ds2; coords[17*dim+2] = 0.5;
1575         /* 17 33 21 */ coords[18*dim+0] =  ds2; coords[18*dim+1] =  ds2; coords[18*dim+2] = 0.5;
1576         /* 18 34 20 */ coords[19*dim+0] = -ds2; coords[19*dim+1] =  ds2; coords[19*dim+2] = 0.5;
1577         /* 29 35 30 */ coords[20*dim+0] = -dis; coords[20*dim+1] = -dis; coords[20*dim+2] = 0.5;
1578         /* 23 36 25 */ coords[21*dim+0] =  dis; coords[21*dim+1] = -dis; coords[21*dim+2] = 0.5;
1579         /* 24 37 26 */ coords[22*dim+0] =  dis; coords[22*dim+1] =  dis; coords[22*dim+2] = 0.5;
1580         /* 27 38 28 */ coords[23*dim+0] = -dis; coords[23*dim+1] =  dis; coords[23*dim+2] = 0.5;
1581       }
1582     }
1583     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1584     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1585     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1586   }
1587   /* Create periodicity */
1588   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1589     PetscReal      L[3];
1590     PetscReal      maxCell[3];
1591     DMBoundaryType bdType[3];
1592     PetscReal      lower[3] = {0.0, 0.0, 0.0};
1593     PetscReal      upper[3] = {1.0, 1.0, 1.5};
1594     PetscInt       i, numZCells = 3;
1595 
1596     bdType[0] = DM_BOUNDARY_NONE;
1597     bdType[1] = DM_BOUNDARY_NONE;
1598     bdType[2] = periodicZ;
1599     for (i = 0; i < dim; i++) {
1600       L[i]       = upper[i] - lower[i];
1601       maxCell[i] = 1.1 * (L[i] / numZCells);
1602     }
1603     ierr = DMSetPeriodicity(*dm, PETSC_TRUE, maxCell, L, bdType);CHKERRQ(ierr);
1604   }
1605   /* Refine topology */
1606   for (r = 0; r < numRefine; ++r) {
1607     DM rdm = NULL;
1608 
1609     ierr = DMRefine(*dm, comm, &rdm);CHKERRQ(ierr);
1610     ierr = DMDestroy(dm);CHKERRQ(ierr);
1611     *dm  = rdm;
1612   }
1613   /* Remap geometry to cylinder
1614        Interior square: Linear interpolation is correct
1615        The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1616        such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
1617 
1618          phi     = arctan(y/x)
1619          d_close = sqrt(1/8 + 1/4 sin^2(phi))
1620          d_far   = sqrt(1/2 + sin^2(phi))
1621 
1622        so we remap them using
1623 
1624          x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1625          y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
1626 
1627        If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1628   */
1629   {
1630     Vec           coordinates;
1631     PetscSection  coordSection;
1632     PetscScalar  *coords;
1633     PetscInt      vStart, vEnd, v;
1634     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1635     const PetscReal ds2 = 0.5*dis;
1636 
1637     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1638     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1639     ierr = DMGetCoordinatesLocal(*dm, &coordinates);CHKERRQ(ierr);
1640     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1641     for (v = vStart; v < vEnd; ++v) {
1642       PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
1643       PetscInt  off;
1644 
1645       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
1646       if ((PetscAbsScalar(coords[off+0]) <= ds2) && (PetscAbsScalar(coords[off+1]) <= ds2)) continue;
1647       x    = PetscRealPart(coords[off]);
1648       y    = PetscRealPart(coords[off+1]);
1649       phi  = PetscAtan2Real(y, x);
1650       sinp = PetscSinReal(phi);
1651       cosp = PetscCosReal(phi);
1652       if ((PetscAbsReal(phi) > PETSC_PI/4.0) && (PetscAbsReal(phi) < 3.0*PETSC_PI/4.0)) {
1653         dc = PetscAbsReal(ds2/sinp);
1654         df = PetscAbsReal(dis/sinp);
1655         xc = ds2*x/PetscAbsReal(y);
1656         yc = ds2*PetscSignReal(y);
1657       } else {
1658         dc = PetscAbsReal(ds2/cosp);
1659         df = PetscAbsReal(dis/cosp);
1660         xc = ds2*PetscSignReal(x);
1661         yc = ds2*y/PetscAbsReal(x);
1662       }
1663       coords[off+0] = xc + (coords[off+0] - xc)*(1.0 - dc)/(df - dc);
1664       coords[off+1] = yc + (coords[off+1] - yc)*(1.0 - dc)/(df - dc);
1665     }
1666     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1667     if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1668       ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr);
1669     }
1670   }
1671   PetscFunctionReturn(0);
1672 }
1673 
1674 /*@
1675   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
1676 
1677   Collective
1678 
1679   Input Parameters:
1680 + comm - The communicator for the DM object
1681 . n    - The number of wedges around the origin
1682 - interpolate - Create edges and faces
1683 
1684   Output Parameter:
1685 . dm  - The DM object
1686 
1687   Level: beginner
1688 
1689 .seealso: DMPlexCreateHexCylinderMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1690 @*/
1691 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
1692 {
1693   const PetscInt dim = 3;
1694   PetscInt       numCells, numVertices, v;
1695   PetscMPIInt    rank;
1696   PetscErrorCode ierr;
1697 
1698   PetscFunctionBegin;
1699   PetscValidPointer(dm, 3);
1700   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1701   if (n < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %D cannot be negative", n);
1702   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1703   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1704   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1705   /* Must create the celltype label here so that we do not automatically try to compute the types */
1706   ierr = DMCreateLabel(*dm, "celltype");CHKERRQ(ierr);
1707   /* Create topology */
1708   {
1709     PetscInt cone[6], c;
1710 
1711     numCells    = !rank ?        n : 0;
1712     numVertices = !rank ?  2*(n+1) : 0;
1713     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1714     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 6);CHKERRQ(ierr);}
1715     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1716     for (c = 0; c < numCells; c++) {
1717       cone[0] =  c+n*1; cone[1] = (c+1)%n+n*1; cone[2] = 0+3*n;
1718       cone[3] =  c+n*2; cone[4] = (c+1)%n+n*2; cone[5] = 1+3*n;
1719       ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
1720       ierr = DMPlexSetCellType(*dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR);CHKERRQ(ierr);
1721     }
1722     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1723     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1724   }
1725   for (v = numCells; v < numCells+numVertices; ++v) {
1726     ierr = DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);
1727   }
1728   /* Interpolate */
1729   if (interpolate) {
1730     DM idm;
1731 
1732     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1733     ierr = DMDestroy(dm);CHKERRQ(ierr);
1734     *dm  = idm;
1735   }
1736   /* Create cylinder geometry */
1737   {
1738     Vec          coordinates;
1739     PetscSection coordSection;
1740     PetscScalar *coords;
1741     PetscInt     coordSize, c;
1742 
1743     /* Build coordinates */
1744     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1745     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1746     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1747     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1748     for (v = numCells; v < numCells+numVertices; ++v) {
1749       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1750       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1751     }
1752     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1753     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1754     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1755     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1756     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1757     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1758     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1759     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1760     for (c = 0; c < numCells; c++) {
1761       coords[(c+0*n)*dim+0] = PetscCosReal(2.0*c*PETSC_PI/n); coords[(c+0*n)*dim+1] = PetscSinReal(2.0*c*PETSC_PI/n); coords[(c+0*n)*dim+2] = 1.0;
1762       coords[(c+1*n)*dim+0] = PetscCosReal(2.0*c*PETSC_PI/n); coords[(c+1*n)*dim+1] = PetscSinReal(2.0*c*PETSC_PI/n); coords[(c+1*n)*dim+2] = 0.0;
1763     }
1764     if (!rank) {
1765       coords[(2*n+0)*dim+0] = 0.0; coords[(2*n+0)*dim+1] = 0.0; coords[(2*n+0)*dim+2] = 1.0;
1766       coords[(2*n+1)*dim+0] = 0.0; coords[(2*n+1)*dim+1] = 0.0; coords[(2*n+1)*dim+2] = 0.0;
1767     }
1768     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1769     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1770     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1771   }
1772   PetscFunctionReturn(0);
1773 }
1774 
1775 PETSC_STATIC_INLINE PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1776 {
1777   PetscReal prod = 0.0;
1778   PetscInt  i;
1779   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
1780   return PetscSqrtReal(prod);
1781 }
1782 PETSC_STATIC_INLINE PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1783 {
1784   PetscReal prod = 0.0;
1785   PetscInt  i;
1786   for (i = 0; i < dim; ++i) prod += x[i]*y[i];
1787   return prod;
1788 }
1789 
1790 /* The first constant is the sphere radius */
1791 static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1792                          const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1793                          const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1794                          PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
1795 {
1796   PetscReal r = PetscRealPart(constants[0]);
1797   PetscReal norm2 = 0.0, fac;
1798   PetscInt  n = uOff[1] - uOff[0], d;
1799 
1800   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
1801   fac = r/PetscSqrtReal(norm2);
1802   for (d = 0; d < n; ++d) f0[d] = u[d]*fac;
1803 }
1804 
1805 /*@
1806   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
1807 
1808   Collective
1809 
1810   Input Parameters:
1811 + comm    - The communicator for the DM object
1812 . dim     - The dimension
1813 . simplex - Use simplices, or tensor product cells
1814 - R       - The radius
1815 
1816   Output Parameter:
1817 . dm  - The DM object
1818 
1819   Level: beginner
1820 
1821 .seealso: DMPlexCreateBallMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1822 @*/
1823 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
1824 {
1825   const PetscInt  embedDim = dim+1;
1826   PetscSection    coordSection;
1827   Vec             coordinates;
1828   PetscScalar    *coords;
1829   PetscReal      *coordsIn;
1830   PetscInt        numCells, numEdges, numVerts, firstVertex, v, firstEdge, coordSize, d, c, e;
1831   PetscMPIInt     rank;
1832   PetscErrorCode  ierr;
1833 
1834   PetscFunctionBegin;
1835   PetscValidPointer(dm, 4);
1836   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1837   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1838   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1839   ierr = DMSetCoordinateDim(*dm, dim+1);CHKERRQ(ierr);
1840   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) *dm), &rank);CHKERRQ(ierr);
1841   switch (dim) {
1842   case 2:
1843     if (simplex) {
1844       DM              idm;
1845       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI*PETSC_PHI)/(1.0 + PETSC_PHI);
1846       const PetscReal edgeLen   = 2.0/(1.0 + PETSC_PHI) * (R/radius);
1847       const PetscInt  degree    = 5;
1848       PetscReal       vertex[3] = {0.0, 1.0/(1.0 + PETSC_PHI), PETSC_PHI/(1.0 + PETSC_PHI)};
1849       PetscInt        s[3]      = {1, 1, 1};
1850       PetscInt        cone[3];
1851       PetscInt       *graph, p, i, j, k;
1852 
1853       vertex[0] *= R/radius; vertex[1] *= R/radius; vertex[2] *= R/radius;
1854       numCells    = !rank ? 20 : 0;
1855       numVerts    = !rank ? 12 : 0;
1856       firstVertex = numCells;
1857       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of
1858 
1859            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
1860 
1861          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
1862          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
1863       */
1864       /* Construct vertices */
1865       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1866       if (!rank) {
1867         for (p = 0, i = 0; p < embedDim; ++p) {
1868           for (s[1] = -1; s[1] < 2; s[1] += 2) {
1869             for (s[2] = -1; s[2] < 2; s[2] += 2) {
1870               for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertex[(d+p)%embedDim];
1871               ++i;
1872             }
1873           }
1874         }
1875       }
1876       /* Construct graph */
1877       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
1878       for (i = 0; i < numVerts; ++i) {
1879         for (j = 0, k = 0; j < numVerts; ++j) {
1880           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
1881         }
1882         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid icosahedron, vertex %D degree %D != %D", i, k, degree);
1883       }
1884       /* Build Topology */
1885       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
1886       for (c = 0; c < numCells; c++) {
1887         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
1888       }
1889       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1890       /* Cells */
1891       for (i = 0, c = 0; i < numVerts; ++i) {
1892         for (j = 0; j < i; ++j) {
1893           for (k = 0; k < j; ++k) {
1894             if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i]) {
1895               cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k;
1896               /* Check orientation */
1897               {
1898                 const PetscInt epsilon[3][3][3] = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}};
1899                 PetscReal normal[3];
1900                 PetscInt  e, f;
1901 
1902                 for (d = 0; d < embedDim; ++d) {
1903                   normal[d] = 0.0;
1904                   for (e = 0; e < embedDim; ++e) {
1905                     for (f = 0; f < embedDim; ++f) {
1906                       normal[d] += epsilon[d][e][f]*(coordsIn[j*embedDim+e] - coordsIn[i*embedDim+e])*(coordsIn[k*embedDim+f] - coordsIn[i*embedDim+f]);
1907                     }
1908                   }
1909                 }
1910                 if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
1911               }
1912               ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
1913             }
1914           }
1915         }
1916       }
1917       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1918       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1919       ierr = PetscFree(graph);CHKERRQ(ierr);
1920       /* Interpolate mesh */
1921       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1922       ierr = DMDestroy(dm);CHKERRQ(ierr);
1923       *dm  = idm;
1924     } else {
1925       /*
1926         12-21--13
1927          |     |
1928         25  4  24
1929          |     |
1930   12-25--9-16--8-24--13
1931    |     |     |     |
1932   23  5 17  0 15  3  22
1933    |     |     |     |
1934   10-20--6-14--7-19--11
1935          |     |
1936         20  1  19
1937          |     |
1938         10-18--11
1939          |     |
1940         23  2  22
1941          |     |
1942         12-21--13
1943        */
1944       PetscInt cone[4], ornt[4];
1945 
1946       numCells    = !rank ?  6 : 0;
1947       numEdges    = !rank ? 12 : 0;
1948       numVerts    = !rank ?  8 : 0;
1949       firstVertex = numCells;
1950       firstEdge   = numCells + numVerts;
1951       /* Build Topology */
1952       ierr = DMPlexSetChart(*dm, 0, numCells+numEdges+numVerts);CHKERRQ(ierr);
1953       for (c = 0; c < numCells; c++) {
1954         ierr = DMPlexSetConeSize(*dm, c, 4);CHKERRQ(ierr);
1955       }
1956       for (e = firstEdge; e < firstEdge+numEdges; ++e) {
1957         ierr = DMPlexSetConeSize(*dm, e, 2);CHKERRQ(ierr);
1958       }
1959       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1960       if (!rank) {
1961         /* Cell 0 */
1962         cone[0] = 14; cone[1] = 15; cone[2] = 16; cone[3] = 17;
1963         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1964         ornt[0] = 0; ornt[1] = 0; ornt[2] = 0; ornt[3] = 0;
1965         ierr = DMPlexSetConeOrientation(*dm, 0, ornt);CHKERRQ(ierr);
1966         /* Cell 1 */
1967         cone[0] = 18; cone[1] = 19; cone[2] = 14; cone[3] = 20;
1968         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1969         ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1970         ierr = DMPlexSetConeOrientation(*dm, 1, ornt);CHKERRQ(ierr);
1971         /* Cell 2 */
1972         cone[0] = 21; cone[1] = 22; cone[2] = 18; cone[3] = 23;
1973         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1974         ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1975         ierr = DMPlexSetConeOrientation(*dm, 2, ornt);CHKERRQ(ierr);
1976         /* Cell 3 */
1977         cone[0] = 19; cone[1] = 22; cone[2] = 24; cone[3] = 15;
1978         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1979         ornt[0] = -2; ornt[1] = -2; ornt[2] = 0; ornt[3] = -2;
1980         ierr = DMPlexSetConeOrientation(*dm, 3, ornt);CHKERRQ(ierr);
1981         /* Cell 4 */
1982         cone[0] = 16; cone[1] = 24; cone[2] = 21; cone[3] = 25;
1983         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1984         ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = 0;
1985         ierr = DMPlexSetConeOrientation(*dm, 4, ornt);CHKERRQ(ierr);
1986         /* Cell 5 */
1987         cone[0] = 20; cone[1] = 17; cone[2] = 25; cone[3] = 23;
1988         ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1989         ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = -2;
1990         ierr = DMPlexSetConeOrientation(*dm, 5, ornt);CHKERRQ(ierr);
1991         /* Edges */
1992         cone[0] =  6; cone[1] =  7;
1993         ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1994         cone[0] =  7; cone[1] =  8;
1995         ierr = DMPlexSetCone(*dm, 15, cone);CHKERRQ(ierr);
1996         cone[0] =  8; cone[1] =  9;
1997         ierr = DMPlexSetCone(*dm, 16, cone);CHKERRQ(ierr);
1998         cone[0] =  9; cone[1] =  6;
1999         ierr = DMPlexSetCone(*dm, 17, cone);CHKERRQ(ierr);
2000         cone[0] = 10; cone[1] = 11;
2001         ierr = DMPlexSetCone(*dm, 18, cone);CHKERRQ(ierr);
2002         cone[0] = 11; cone[1] =  7;
2003         ierr = DMPlexSetCone(*dm, 19, cone);CHKERRQ(ierr);
2004         cone[0] =  6; cone[1] = 10;
2005         ierr = DMPlexSetCone(*dm, 20, cone);CHKERRQ(ierr);
2006         cone[0] = 12; cone[1] = 13;
2007         ierr = DMPlexSetCone(*dm, 21, cone);CHKERRQ(ierr);
2008         cone[0] = 13; cone[1] = 11;
2009         ierr = DMPlexSetCone(*dm, 22, cone);CHKERRQ(ierr);
2010         cone[0] = 10; cone[1] = 12;
2011         ierr = DMPlexSetCone(*dm, 23, cone);CHKERRQ(ierr);
2012         cone[0] = 13; cone[1] =  8;
2013         ierr = DMPlexSetCone(*dm, 24, cone);CHKERRQ(ierr);
2014         cone[0] = 12; cone[1] =  9;
2015         ierr = DMPlexSetCone(*dm, 25, cone);CHKERRQ(ierr);
2016       }
2017       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
2018       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
2019       /* Build coordinates */
2020       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
2021       if (!rank) {
2022         coordsIn[0*embedDim+0] = -R; coordsIn[0*embedDim+1] =  R; coordsIn[0*embedDim+2] = -R;
2023         coordsIn[1*embedDim+0] =  R; coordsIn[1*embedDim+1] =  R; coordsIn[1*embedDim+2] = -R;
2024         coordsIn[2*embedDim+0] =  R; coordsIn[2*embedDim+1] = -R; coordsIn[2*embedDim+2] = -R;
2025         coordsIn[3*embedDim+0] = -R; coordsIn[3*embedDim+1] = -R; coordsIn[3*embedDim+2] = -R;
2026         coordsIn[4*embedDim+0] = -R; coordsIn[4*embedDim+1] =  R; coordsIn[4*embedDim+2] =  R;
2027         coordsIn[5*embedDim+0] =  R; coordsIn[5*embedDim+1] =  R; coordsIn[5*embedDim+2] =  R;
2028         coordsIn[6*embedDim+0] = -R; coordsIn[6*embedDim+1] = -R; coordsIn[6*embedDim+2] =  R;
2029         coordsIn[7*embedDim+0] =  R; coordsIn[7*embedDim+1] = -R; coordsIn[7*embedDim+2] =  R;
2030       }
2031     }
2032     break;
2033   case 3:
2034     if (simplex) {
2035       DM              idm;
2036       const PetscReal edgeLen         = 1.0/PETSC_PHI;
2037       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
2038       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
2039       PetscReal       vertexC[4]      = {0.5, 0.5*PETSC_PHI, 0.5/PETSC_PHI, 0.0};
2040       const PetscInt  degree          = 12;
2041       PetscInt        s[4]            = {1, 1, 1};
2042       PetscInt        evenPerm[12][4] = {{0, 1, 2, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 3, 2, 0},
2043                                          {2, 0, 1, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 2, 1, 0}};
2044       PetscInt        cone[4];
2045       PetscInt       *graph, p, i, j, k, l;
2046 
2047       vertexA[0] *= R; vertexA[1] *= R; vertexA[2] *= R; vertexA[3] *= R;
2048       vertexB[0] *= R; vertexB[1] *= R; vertexB[2] *= R; vertexB[3] *= R;
2049       vertexC[0] *= R; vertexC[1] *= R; vertexC[2] *= R; vertexC[3] *= R;
2050       numCells    = !rank ? 600 : 0;
2051       numVerts    = !rank ? 120 : 0;
2052       firstVertex = numCells;
2053       /* Use the 600-cell, which for a unit sphere has coordinates which are
2054 
2055            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
2056                (\pm 1,    0,       0,      0)  all cyclic permutations   8
2057            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
2058 
2059          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
2060          length is then given by 1/\phi = 0.61803.
2061 
2062          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
2063          http://mathworld.wolfram.com/600-Cell.html
2064       */
2065       /* Construct vertices */
2066       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
2067       i    = 0;
2068       if (!rank) {
2069         for (s[0] = -1; s[0] < 2; s[0] += 2) {
2070           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2071             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2072               for (s[3] = -1; s[3] < 2; s[3] += 2) {
2073                 for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[d]*vertexA[d];
2074                 ++i;
2075               }
2076             }
2077           }
2078         }
2079         for (p = 0; p < embedDim; ++p) {
2080           s[1] = s[2] = s[3] = 1;
2081           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2082             for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertexB[(d+p)%embedDim];
2083             ++i;
2084           }
2085         }
2086         for (p = 0; p < 12; ++p) {
2087           s[3] = 1;
2088           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2089             for (s[1] = -1; s[1] < 2; s[1] += 2) {
2090               for (s[2] = -1; s[2] < 2; s[2] += 2) {
2091                 for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[evenPerm[p][d]]*vertexC[evenPerm[p][d]];
2092                 ++i;
2093               }
2094             }
2095           }
2096         }
2097       }
2098       if (i != numVerts) SETERRQ2(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertices %D != %D", i, numVerts);
2099       /* Construct graph */
2100       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
2101       for (i = 0; i < numVerts; ++i) {
2102         for (j = 0, k = 0; j < numVerts; ++j) {
2103           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
2104         }
2105         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertex %D degree %D != %D", i, k, degree);
2106       }
2107       /* Build Topology */
2108       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
2109       for (c = 0; c < numCells; c++) {
2110         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
2111       }
2112       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
2113       /* Cells */
2114       if (!rank) {
2115         for (i = 0, c = 0; i < numVerts; ++i) {
2116           for (j = 0; j < i; ++j) {
2117             for (k = 0; k < j; ++k) {
2118               for (l = 0; l < k; ++l) {
2119                 if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i] &&
2120                     graph[l*numVerts+i] && graph[l*numVerts+j] && graph[l*numVerts+k]) {
2121                   cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k; cone[3] = firstVertex+l;
2122                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
2123                   {
2124                     const PetscInt epsilon[4][4][4][4] = {{{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2125                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  1}, { 0,  0, -1, 0}},
2126                                                            {{0,  0,  0,  0}, { 0, 0,  0, -1}, { 0,  0, 0,  0}, { 0,  1,  0, 0}},
2127                                                            {{0,  0,  0,  0}, { 0, 0,  1,  0}, { 0, -1, 0,  0}, { 0,  0,  0, 0}}},
2128 
2129                                                           {{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0, -1}, { 0,  0,  1, 0}},
2130                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2131                                                            {{0,  0,  0,  1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, {-1,  0,  0, 0}},
2132                                                            {{0,  0, -1,  0}, { 0, 0,  0,  0}, { 1,  0, 0,  0}, { 0,  0,  0, 0}}},
2133 
2134                                                           {{{0,  0,  0,  0}, { 0, 0,  0,  1}, { 0,  0, 0,  0}, { 0, -1,  0, 0}},
2135                                                            {{0,  0,  0, -1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 1,  0,  0, 0}},
2136                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2137                                                            {{0,  1,  0,  0}, {-1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}},
2138 
2139                                                           {{{0,  0,  0,  0}, { 0, 0, -1,  0}, { 0,  1, 0,  0}, { 0,  0,  0, 0}},
2140                                                            {{0,  0,  1,  0}, { 0, 0,  0,  0}, {-1,  0, 0,  0}, { 0,  0,  0, 0}},
2141                                                            {{0, -1,  0,  0}, { 1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2142                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}}};
2143                     PetscReal normal[4];
2144                     PetscInt  e, f, g;
2145 
2146                     for (d = 0; d < embedDim; ++d) {
2147                       normal[d] = 0.0;
2148                       for (e = 0; e < embedDim; ++e) {
2149                         for (f = 0; f < embedDim; ++f) {
2150                           for (g = 0; g < embedDim; ++g) {
2151                             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]);
2152                           }
2153                         }
2154                       }
2155                     }
2156                     if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
2157                   }
2158                   ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
2159                 }
2160               }
2161             }
2162           }
2163         }
2164       }
2165       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
2166       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
2167       ierr = PetscFree(graph);CHKERRQ(ierr);
2168       /* Interpolate mesh */
2169       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2170       ierr = DMDestroy(dm);CHKERRQ(ierr);
2171       *dm  = idm;
2172       break;
2173     }
2174   default: SETERRQ1(comm, PETSC_ERR_SUP, "Unsupported dimension for sphere: %D", dim);
2175   }
2176   /* Create coordinates */
2177   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
2178   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2179   ierr = PetscSectionSetFieldComponents(coordSection, 0, embedDim);CHKERRQ(ierr);
2180   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numVerts);CHKERRQ(ierr);
2181   for (v = firstVertex; v < firstVertex+numVerts; ++v) {
2182     ierr = PetscSectionSetDof(coordSection, v, embedDim);CHKERRQ(ierr);
2183     ierr = PetscSectionSetFieldDof(coordSection, v, 0, embedDim);CHKERRQ(ierr);
2184   }
2185   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2186   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
2187   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
2188   ierr = VecSetBlockSize(coordinates, embedDim);CHKERRQ(ierr);
2189   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2190   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2191   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
2192   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2193   for (v = 0; v < numVerts; ++v) for (d = 0; d < embedDim; ++d) {coords[v*embedDim+d] = coordsIn[v*embedDim+d];}
2194   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2195   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
2196   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2197   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
2198   /* Create coordinate function space */
2199   {
2200     DM          cdm;
2201     PetscDS     cds;
2202     PetscFE     fe;
2203     PetscScalar radius = R;
2204     PetscInt    dT, dE;
2205 
2206     ierr = DMGetCoordinateDM(*dm, &cdm);CHKERRQ(ierr);
2207     ierr = DMGetDimension(*dm, &dT);CHKERRQ(ierr);
2208     ierr = DMGetCoordinateDim(*dm, &dE);CHKERRQ(ierr);
2209     ierr = PetscFECreateLagrange(PETSC_COMM_SELF, dT, dE, simplex, 1, -1, &fe);CHKERRQ(ierr);
2210     ierr = DMSetField(cdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
2211     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
2212     ierr = DMCreateDS(cdm);CHKERRQ(ierr);
2213 
2214     ierr = DMGetDS(cdm, &cds);CHKERRQ(ierr);
2215     ierr = PetscDSSetConstants(cds, 1, &radius);CHKERRQ(ierr);
2216   }
2217   ((DM_Plex *) (*dm)->data)->coordFunc = snapToSphere;
2218   PetscFunctionReturn(0);
2219 }
2220 
2221 /*@
2222   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.
2223 
2224   Collective
2225 
2226   Input Parameters:
2227 + comm  - The communicator for the DM object
2228 . dim   - The dimension
2229 - R     - The radius
2230 
2231   Output Parameter:
2232 . dm  - The DM object
2233 
2234   Options Database Keys:
2235 - bd_dm_refine - This will refine the surface mesh preserving the sphere geometry
2236 
2237   Level: beginner
2238 
2239 .seealso: DMPlexCreateSphereMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
2240 @*/
2241 PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
2242 {
2243   DM             sdm;
2244   DMLabel        bdlabel;
2245   PetscErrorCode ierr;
2246 
2247   PetscFunctionBegin;
2248   ierr = DMPlexCreateSphereMesh(comm, dim-1, PETSC_TRUE, R, &sdm);CHKERRQ(ierr);
2249   ierr = PetscObjectSetOptionsPrefix((PetscObject) sdm, "bd_");CHKERRQ(ierr);
2250   ierr = DMSetFromOptions(sdm);CHKERRQ(ierr);
2251   ierr = DMPlexGenerate(sdm, NULL, PETSC_TRUE, dm);CHKERRQ(ierr);
2252   ierr = DMDestroy(&sdm);CHKERRQ(ierr);
2253   ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
2254   ierr = DMGetLabel(*dm, "marker", &bdlabel);CHKERRQ(ierr);
2255   ierr = DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel);CHKERRQ(ierr);
2256   ierr = DMPlexLabelComplete(*dm, bdlabel);CHKERRQ(ierr);
2257   PetscFunctionReturn(0);
2258 }
2259 
2260 /* External function declarations here */
2261 extern PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling);
2262 extern PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat);
2263 extern PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mat);
2264 extern PetscErrorCode DMCreateLocalSection_Plex(DM dm);
2265 extern PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm);
2266 extern PetscErrorCode DMCreateMatrix_Plex(DM dm,  Mat *J);
2267 extern PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm);
2268 extern PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field);
2269 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm);
2270 extern PetscErrorCode DMSetUp_Plex(DM dm);
2271 extern PetscErrorCode DMDestroy_Plex(DM dm);
2272 extern PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer);
2273 extern PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer);
2274 extern PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm);
2275 extern PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm);
2276 static PetscErrorCode DMInitialize_Plex(DM dm);
2277 
2278 /* Replace dm with the contents of dmNew
2279    - Share the DM_Plex structure
2280    - Share the coordinates
2281    - Share the SF
2282 */
2283 static PetscErrorCode DMPlexReplace_Static(DM dm, DM dmNew)
2284 {
2285   PetscSF               sf;
2286   DM                    coordDM, coarseDM;
2287   DMField               coordField;
2288   Vec                   coords;
2289   PetscBool             isper;
2290   const PetscReal      *maxCell, *L;
2291   const DMBoundaryType *bd;
2292   PetscErrorCode        ierr;
2293 
2294   PetscFunctionBegin;
2295   ierr = DMGetPointSF(dmNew, &sf);CHKERRQ(ierr);
2296   ierr = DMSetPointSF(dm, sf);CHKERRQ(ierr);
2297   ierr = DMGetCoordinateDM(dmNew, &coordDM);CHKERRQ(ierr);
2298   ierr = DMGetCoordinatesLocal(dmNew, &coords);CHKERRQ(ierr);
2299   ierr = DMGetCoordinateField(dmNew, &coordField);CHKERRQ(ierr);
2300   ierr = DMSetCoordinateDM(dm, coordDM);CHKERRQ(ierr);
2301   ierr = DMSetCoordinatesLocal(dm, coords);CHKERRQ(ierr);
2302   ierr = DMSetCoordinateField(dm, coordField);CHKERRQ(ierr);
2303   ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
2304   ierr = DMSetPeriodicity(dmNew, isper, maxCell, L, bd);CHKERRQ(ierr);
2305   ierr = DMDestroy_Plex(dm);CHKERRQ(ierr);
2306   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
2307   dm->data = dmNew->data;
2308   ((DM_Plex *) dmNew->data)->refct++;
2309   ierr = DMDestroyLabelLinkList_Internal(dm);CHKERRQ(ierr);
2310   ierr = DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE);CHKERRQ(ierr);
2311   ierr = DMGetCoarseDM(dmNew,&coarseDM);CHKERRQ(ierr);
2312   ierr = DMSetCoarseDM(dm,coarseDM);CHKERRQ(ierr);
2313   PetscFunctionReturn(0);
2314 }
2315 
2316 /* Swap dm with the contents of dmNew
2317    - Swap the DM_Plex structure
2318    - Swap the coordinates
2319    - Swap the point PetscSF
2320 */
2321 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
2322 {
2323   DM              coordDMA, coordDMB;
2324   Vec             coordsA,  coordsB;
2325   PetscSF         sfA,      sfB;
2326   void            *tmp;
2327   DMLabelLink     listTmp;
2328   DMLabel         depthTmp;
2329   PetscInt        tmpI;
2330   PetscErrorCode  ierr;
2331 
2332   PetscFunctionBegin;
2333   ierr = DMGetPointSF(dmA, &sfA);CHKERRQ(ierr);
2334   ierr = DMGetPointSF(dmB, &sfB);CHKERRQ(ierr);
2335   ierr = PetscObjectReference((PetscObject) sfA);CHKERRQ(ierr);
2336   ierr = DMSetPointSF(dmA, sfB);CHKERRQ(ierr);
2337   ierr = DMSetPointSF(dmB, sfA);CHKERRQ(ierr);
2338   ierr = PetscObjectDereference((PetscObject) sfA);CHKERRQ(ierr);
2339 
2340   ierr = DMGetCoordinateDM(dmA, &coordDMA);CHKERRQ(ierr);
2341   ierr = DMGetCoordinateDM(dmB, &coordDMB);CHKERRQ(ierr);
2342   ierr = PetscObjectReference((PetscObject) coordDMA);CHKERRQ(ierr);
2343   ierr = DMSetCoordinateDM(dmA, coordDMB);CHKERRQ(ierr);
2344   ierr = DMSetCoordinateDM(dmB, coordDMA);CHKERRQ(ierr);
2345   ierr = PetscObjectDereference((PetscObject) coordDMA);CHKERRQ(ierr);
2346 
2347   ierr = DMGetCoordinatesLocal(dmA, &coordsA);CHKERRQ(ierr);
2348   ierr = DMGetCoordinatesLocal(dmB, &coordsB);CHKERRQ(ierr);
2349   ierr = PetscObjectReference((PetscObject) coordsA);CHKERRQ(ierr);
2350   ierr = DMSetCoordinatesLocal(dmA, coordsB);CHKERRQ(ierr);
2351   ierr = DMSetCoordinatesLocal(dmB, coordsA);CHKERRQ(ierr);
2352   ierr = PetscObjectDereference((PetscObject) coordsA);CHKERRQ(ierr);
2353 
2354   tmp       = dmA->data;
2355   dmA->data = dmB->data;
2356   dmB->data = tmp;
2357   listTmp   = dmA->labels;
2358   dmA->labels = dmB->labels;
2359   dmB->labels = listTmp;
2360   depthTmp  = dmA->depthLabel;
2361   dmA->depthLabel = dmB->depthLabel;
2362   dmB->depthLabel = depthTmp;
2363   depthTmp  = dmA->celltypeLabel;
2364   dmA->celltypeLabel = dmB->celltypeLabel;
2365   dmB->celltypeLabel = depthTmp;
2366   tmpI         = dmA->levelup;
2367   dmA->levelup = dmB->levelup;
2368   dmB->levelup = tmpI;
2369   PetscFunctionReturn(0);
2370 }
2371 
2372 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
2373 {
2374   DM_Plex       *mesh = (DM_Plex*) dm->data;
2375   PetscBool      flg;
2376   PetscErrorCode ierr;
2377 
2378   PetscFunctionBegin;
2379   /* Handle viewing */
2380   ierr = PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL);CHKERRQ(ierr);
2381   ierr = PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL,0);CHKERRQ(ierr);
2382   ierr = PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL);CHKERRQ(ierr);
2383   ierr = PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL,0);CHKERRQ(ierr);
2384   ierr = DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg);CHKERRQ(ierr);
2385   if (flg) {ierr = PetscLogDefaultBegin();CHKERRQ(ierr);}
2386   /* Point Location */
2387   ierr = PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL);CHKERRQ(ierr);
2388   /* Partitioning and distribution */
2389   ierr = PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL);CHKERRQ(ierr);
2390   /* Generation and remeshing */
2391   ierr = PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL);CHKERRQ(ierr);
2392   /* Projection behavior */
2393   ierr = PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maxmimum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL,0);CHKERRQ(ierr);
2394   ierr = PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL);CHKERRQ(ierr);
2395   ierr = PetscOptionsEnum("-dm_plex_cell_refiner", "Strategy for cell refinment", "ex40.c", DMPlexCellRefinerTypes, (PetscEnum) mesh->cellRefiner, (PetscEnum *) &mesh->cellRefiner, NULL);CHKERRQ(ierr);
2396   /* Checking structure */
2397   {
2398     PetscBool   flg = PETSC_FALSE, flg2 = PETSC_FALSE, all = PETSC_FALSE;
2399 
2400     ierr = PetscOptionsBool("-dm_plex_check_all", "Perform all checks", NULL, PETSC_FALSE, &all, &flg2);CHKERRQ(ierr);
2401     ierr = PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2402     if (all || (flg && flg2)) {ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);}
2403     ierr = 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);CHKERRQ(ierr);
2404     if (all || (flg && flg2)) {ierr = DMPlexCheckSkeleton(dm, 0);CHKERRQ(ierr);}
2405     ierr = 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);CHKERRQ(ierr);
2406     if (all || (flg && flg2)) {ierr = DMPlexCheckFaces(dm, 0);CHKERRQ(ierr);}
2407     ierr = PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2408     if (all || (flg && flg2)) {ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);}
2409     ierr = PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2410     if (all || (flg && flg2)) {ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);}
2411     ierr = PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2412     if (all || (flg && flg2)) {ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);}
2413     ierr = PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2414     if (flg && flg2) {ierr = DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE);CHKERRQ(ierr);}
2415   }
2416 
2417   ierr = PetscPartitionerSetFromOptions(mesh->partitioner);CHKERRQ(ierr);
2418   PetscFunctionReturn(0);
2419 }
2420 
2421 static PetscErrorCode DMSetFromOptions_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
2422 {
2423   PetscInt       prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0;
2424   PetscBool      distribute = PETSC_FALSE, isHierarchy;
2425   PetscErrorCode ierr;
2426 
2427   PetscFunctionBegin;
2428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2429   ierr = PetscOptionsHead(PetscOptionsObject,"DMPlex Options");CHKERRQ(ierr);
2430   /* Handle DMPlex refinement before distribution */
2431   ierr = PetscOptionsBoundedInt("-dm_refine_pre", "The number of uniform refinements before distribution", "DMCreate", prerefine, &prerefine, NULL,0);CHKERRQ(ierr);
2432   if (prerefine) {ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE);CHKERRQ(ierr);}
2433   for (r = 0; r < prerefine; ++r) {
2434     DM             rdm;
2435     PetscPointFunc coordFunc = ((DM_Plex*) dm->data)->coordFunc;
2436 
2437     ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2438     ierr = DMRefine(dm, PetscObjectComm((PetscObject) dm), &rdm);CHKERRQ(ierr);
2439     /* Total hack since we do not pass in a pointer */
2440     ierr = DMPlexReplace_Static(dm, rdm);CHKERRQ(ierr);
2441     ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2442     if (coordFunc) {
2443       ierr = DMPlexRemapGeometry(dm, 0.0, coordFunc);CHKERRQ(ierr);
2444       ((DM_Plex*) dm->data)->coordFunc = coordFunc;
2445     }
2446     ierr = DMDestroy(&rdm);CHKERRQ(ierr);
2447   }
2448   /* Handle DMPlex distribution */
2449   ierr = PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMCreate", distribute, &distribute, NULL);CHKERRQ(ierr);
2450   ierr = PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMCreate", overlap, &overlap, NULL, 0);CHKERRQ(ierr);
2451   if (distribute) {
2452     DM               pdm = NULL;
2453     PetscPartitioner part;
2454 
2455     ierr = DMPlexGetPartitioner(dm, &part);CHKERRQ(ierr);
2456     ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr);
2457     ierr = DMPlexDistribute(dm, overlap, NULL, &pdm);CHKERRQ(ierr);
2458     if (pdm) {
2459       ierr = DMPlexReplace_Static(dm, pdm);CHKERRQ(ierr);
2460       ierr = DMDestroy(&pdm);CHKERRQ(ierr);
2461     }
2462   }
2463   /* Handle DMPlex refinement */
2464   ierr = PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL,0);CHKERRQ(ierr);
2465   ierr = PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy,0);CHKERRQ(ierr);
2466   if (refine) {ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE);CHKERRQ(ierr);}
2467   if (refine && isHierarchy) {
2468     DM *dms, coarseDM;
2469 
2470     ierr = DMGetCoarseDM(dm, &coarseDM);CHKERRQ(ierr);
2471     ierr = PetscObjectReference((PetscObject)coarseDM);CHKERRQ(ierr);
2472     ierr = PetscMalloc1(refine,&dms);CHKERRQ(ierr);
2473     ierr = DMRefineHierarchy(dm, refine, dms);CHKERRQ(ierr);
2474     /* Total hack since we do not pass in a pointer */
2475     ierr = DMPlexSwap_Static(dm, dms[refine-1]);CHKERRQ(ierr);
2476     if (refine == 1) {
2477       ierr = DMSetCoarseDM(dm, dms[0]);CHKERRQ(ierr);
2478       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
2479     } else {
2480       ierr = DMSetCoarseDM(dm, dms[refine-2]);CHKERRQ(ierr);
2481       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
2482       ierr = DMSetCoarseDM(dms[0], dms[refine-1]);CHKERRQ(ierr);
2483       ierr = DMPlexSetRegularRefinement(dms[0], PETSC_TRUE);CHKERRQ(ierr);
2484     }
2485     ierr = DMSetCoarseDM(dms[refine-1], coarseDM);CHKERRQ(ierr);
2486     ierr = PetscObjectDereference((PetscObject)coarseDM);CHKERRQ(ierr);
2487     /* Free DMs */
2488     for (r = 0; r < refine; ++r) {
2489       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
2490       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
2491     }
2492     ierr = PetscFree(dms);CHKERRQ(ierr);
2493   } else {
2494     for (r = 0; r < refine; ++r) {
2495       DM refinedMesh;
2496       PetscPointFunc coordFunc = ((DM_Plex*) dm->data)->coordFunc;
2497 
2498       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2499       ierr = DMRefine(dm, PetscObjectComm((PetscObject) dm), &refinedMesh);CHKERRQ(ierr);
2500       /* Total hack since we do not pass in a pointer */
2501       ierr = DMPlexReplace_Static(dm, refinedMesh);CHKERRQ(ierr);
2502       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2503       if (coordFunc) {
2504         ierr = DMPlexRemapGeometry(dm, 0.0, coordFunc);CHKERRQ(ierr);
2505         ((DM_Plex*) dm->data)->coordFunc = coordFunc;
2506       }
2507       ierr = DMDestroy(&refinedMesh);CHKERRQ(ierr);
2508     }
2509   }
2510   /* Handle DMPlex coarsening */
2511   ierr = PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL,0);CHKERRQ(ierr);
2512   ierr = PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy,0);CHKERRQ(ierr);
2513   if (coarsen && isHierarchy) {
2514     DM *dms;
2515 
2516     ierr = PetscMalloc1(coarsen, &dms);CHKERRQ(ierr);
2517     ierr = DMCoarsenHierarchy(dm, coarsen, dms);CHKERRQ(ierr);
2518     /* Free DMs */
2519     for (r = 0; r < coarsen; ++r) {
2520       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
2521       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
2522     }
2523     ierr = PetscFree(dms);CHKERRQ(ierr);
2524   } else {
2525     for (r = 0; r < coarsen; ++r) {
2526       DM coarseMesh;
2527 
2528       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2529       ierr = DMCoarsen(dm, PetscObjectComm((PetscObject) dm), &coarseMesh);CHKERRQ(ierr);
2530       /* Total hack since we do not pass in a pointer */
2531       ierr = DMPlexReplace_Static(dm, coarseMesh);CHKERRQ(ierr);
2532       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2533       ierr = DMDestroy(&coarseMesh);CHKERRQ(ierr);
2534     }
2535   }
2536   /* Handle */
2537   ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2538   ierr = PetscOptionsTail();CHKERRQ(ierr);
2539   PetscFunctionReturn(0);
2540 }
2541 
2542 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm,Vec *vec)
2543 {
2544   PetscErrorCode ierr;
2545 
2546   PetscFunctionBegin;
2547   ierr = DMCreateGlobalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2548   /* ierr = VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM);CHKERRQ(ierr); */
2549   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex);CHKERRQ(ierr);
2550   ierr = VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void)) VecView_Plex_Native);CHKERRQ(ierr);
2551   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex);CHKERRQ(ierr);
2552   ierr = VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void)) VecLoad_Plex_Native);CHKERRQ(ierr);
2553   PetscFunctionReturn(0);
2554 }
2555 
2556 static PetscErrorCode DMCreateLocalVector_Plex(DM dm,Vec *vec)
2557 {
2558   PetscErrorCode ierr;
2559 
2560   PetscFunctionBegin;
2561   ierr = DMCreateLocalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2562   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex_Local);CHKERRQ(ierr);
2563   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex_Local);CHKERRQ(ierr);
2564   PetscFunctionReturn(0);
2565 }
2566 
2567 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
2568 {
2569   PetscInt       depth, d;
2570   PetscErrorCode ierr;
2571 
2572   PetscFunctionBegin;
2573   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2574   if (depth == 1) {
2575     ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
2576     if (dim == 0)      {ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);}
2577     else if (dim == d) {ierr = DMPlexGetDepthStratum(dm, 1, pStart, pEnd);CHKERRQ(ierr);}
2578     else               {*pStart = 0; *pEnd = 0;}
2579   } else {
2580     ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);
2581   }
2582   PetscFunctionReturn(0);
2583 }
2584 
2585 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
2586 {
2587   PetscSF           sf;
2588   PetscInt          niranks, njranks, n;
2589   const PetscMPIInt *iranks, *jranks;
2590   DM_Plex           *data = (DM_Plex*) dm->data;
2591   PetscErrorCode    ierr;
2592 
2593   PetscFunctionBegin;
2594   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2595   if (!data->neighbors) {
2596     ierr = PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL);CHKERRQ(ierr);
2597     ierr = PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL);CHKERRQ(ierr);
2598     ierr = PetscMalloc1(njranks + niranks + 1, &data->neighbors);CHKERRQ(ierr);
2599     ierr = PetscArraycpy(data->neighbors + 1, jranks, njranks);CHKERRQ(ierr);
2600     ierr = PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks);CHKERRQ(ierr);
2601     n = njranks + niranks;
2602     ierr = PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1);CHKERRQ(ierr);
2603     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
2604     ierr = PetscMPIIntCast(n, data->neighbors);CHKERRQ(ierr);
2605   }
2606   if (nranks) *nranks = data->neighbors[0];
2607   if (ranks) {
2608     if (data->neighbors[0]) *ranks = data->neighbors + 1;
2609     else                    *ranks = NULL;
2610   }
2611   PetscFunctionReturn(0);
2612 }
2613 
2614 static PetscErrorCode DMInitialize_Plex(DM dm)
2615 {
2616   PetscErrorCode ierr;
2617 
2618   PetscFunctionBegin;
2619   dm->ops->view                            = DMView_Plex;
2620   dm->ops->load                            = DMLoad_Plex;
2621   dm->ops->setfromoptions                  = DMSetFromOptions_Plex;
2622   dm->ops->clone                           = DMClone_Plex;
2623   dm->ops->setup                           = DMSetUp_Plex;
2624   dm->ops->createlocalsection              = DMCreateLocalSection_Plex;
2625   dm->ops->createdefaultconstraints        = DMCreateDefaultConstraints_Plex;
2626   dm->ops->createglobalvector              = DMCreateGlobalVector_Plex;
2627   dm->ops->createlocalvector               = DMCreateLocalVector_Plex;
2628   dm->ops->getlocaltoglobalmapping         = NULL;
2629   dm->ops->createfieldis                   = NULL;
2630   dm->ops->createcoordinatedm              = DMCreateCoordinateDM_Plex;
2631   dm->ops->createcoordinatefield           = DMCreateCoordinateField_Plex;
2632   dm->ops->getcoloring                     = NULL;
2633   dm->ops->creatematrix                    = DMCreateMatrix_Plex;
2634   dm->ops->createinterpolation             = DMCreateInterpolation_Plex;
2635   dm->ops->createmassmatrix                = DMCreateMassMatrix_Plex;
2636   dm->ops->createinjection                 = DMCreateInjection_Plex;
2637   dm->ops->refine                          = DMRefine_Plex;
2638   dm->ops->coarsen                         = DMCoarsen_Plex;
2639   dm->ops->refinehierarchy                 = DMRefineHierarchy_Plex;
2640   dm->ops->coarsenhierarchy                = DMCoarsenHierarchy_Plex;
2641   dm->ops->adaptlabel                      = DMAdaptLabel_Plex;
2642   dm->ops->adaptmetric                     = DMAdaptMetric_Plex;
2643   dm->ops->globaltolocalbegin              = NULL;
2644   dm->ops->globaltolocalend                = NULL;
2645   dm->ops->localtoglobalbegin              = NULL;
2646   dm->ops->localtoglobalend                = NULL;
2647   dm->ops->destroy                         = DMDestroy_Plex;
2648   dm->ops->createsubdm                     = DMCreateSubDM_Plex;
2649   dm->ops->createsuperdm                   = DMCreateSuperDM_Plex;
2650   dm->ops->getdimpoints                    = DMGetDimPoints_Plex;
2651   dm->ops->locatepoints                    = DMLocatePoints_Plex;
2652   dm->ops->projectfunctionlocal            = DMProjectFunctionLocal_Plex;
2653   dm->ops->projectfunctionlabellocal       = DMProjectFunctionLabelLocal_Plex;
2654   dm->ops->projectfieldlocal               = DMProjectFieldLocal_Plex;
2655   dm->ops->projectfieldlabellocal          = DMProjectFieldLabelLocal_Plex;
2656   dm->ops->projectbdfieldlabellocal        = DMProjectBdFieldLabelLocal_Plex;
2657   dm->ops->computel2diff                   = DMComputeL2Diff_Plex;
2658   dm->ops->computel2gradientdiff           = DMComputeL2GradientDiff_Plex;
2659   dm->ops->computel2fielddiff              = DMComputeL2FieldDiff_Plex;
2660   dm->ops->getneighbors                    = DMGetNeighbors_Plex;
2661   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C",DMPlexInsertBoundaryValues_Plex);CHKERRQ(ierr);
2662   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C",DMPlexInsertTimeDerivativeBoundaryValues_Plex);CHKERRQ(ierr);
2663   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",DMSetUpGLVisViewer_Plex);CHKERRQ(ierr);
2664   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_Plex);CHKERRQ(ierr);
2665   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMPlexGetOverlap_Plex);CHKERRQ(ierr);
2666   PetscFunctionReturn(0);
2667 }
2668 
2669 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
2670 {
2671   DM_Plex        *mesh = (DM_Plex *) dm->data;
2672   PetscErrorCode ierr;
2673 
2674   PetscFunctionBegin;
2675   mesh->refct++;
2676   (*newdm)->data = mesh;
2677   ierr = PetscObjectChangeTypeName((PetscObject) *newdm, DMPLEX);CHKERRQ(ierr);
2678   ierr = DMInitialize_Plex(*newdm);CHKERRQ(ierr);
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 /*MC
2683   DMPLEX = "plex" - A DM object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
2684                     In the local representation, Vecs contain all unknowns in the interior and shared boundary. This is
2685                     specified by a PetscSection object. Ownership in the global representation is determined by
2686                     ownership of the underlying DMPlex points. This is specified by another PetscSection object.
2687 
2688   Options Database Keys:
2689 + -dm_plex_hash_location             - Use grid hashing for point location
2690 . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
2691 . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
2692 . -dm_plex_max_projection_height     - Maxmimum mesh point height used to project locally
2693 . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
2694 . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
2695 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
2696 . -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
2697 . -dm_plex_check_geometry            - Check that cells have positive volume
2698 . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
2699 . -dm_plex_view_scale <num>          - Scale the TikZ
2700 - -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
2701 
2702 
2703   Level: intermediate
2704 
2705 .seealso: DMType, DMPlexCreate(), DMCreate(), DMSetType()
2706 M*/
2707 
2708 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
2709 {
2710   DM_Plex       *mesh;
2711   PetscInt       unit;
2712   PetscErrorCode ierr;
2713 
2714   PetscFunctionBegin;
2715   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2716   ierr     = PetscNewLog(dm,&mesh);CHKERRQ(ierr);
2717   dm->dim  = 0;
2718   dm->data = mesh;
2719 
2720   mesh->refct             = 1;
2721   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection);CHKERRQ(ierr);
2722   mesh->maxConeSize       = 0;
2723   mesh->cones             = NULL;
2724   mesh->coneOrientations  = NULL;
2725   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection);CHKERRQ(ierr);
2726   mesh->maxSupportSize    = 0;
2727   mesh->supports          = NULL;
2728   mesh->refinementUniform = PETSC_TRUE;
2729   mesh->refinementLimit   = -1.0;
2730   mesh->interpolated      = DMPLEX_INTERPOLATED_INVALID;
2731   mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID;
2732 
2733   mesh->facesTmp = NULL;
2734 
2735   mesh->tetgenOpts   = NULL;
2736   mesh->triangleOpts = NULL;
2737   ierr = PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner);CHKERRQ(ierr);
2738   mesh->remeshBd     = PETSC_FALSE;
2739 
2740   mesh->subpointMap = NULL;
2741 
2742   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
2743 
2744   mesh->regularRefinement   = PETSC_FALSE;
2745   mesh->depthState          = -1;
2746   mesh->celltypeState       = -1;
2747   mesh->globalVertexNumbers = NULL;
2748   mesh->globalCellNumbers   = NULL;
2749   mesh->anchorSection       = NULL;
2750   mesh->anchorIS            = NULL;
2751   mesh->createanchors       = NULL;
2752   mesh->computeanchormatrix = NULL;
2753   mesh->parentSection       = NULL;
2754   mesh->parents             = NULL;
2755   mesh->childIDs            = NULL;
2756   mesh->childSection        = NULL;
2757   mesh->children            = NULL;
2758   mesh->referenceTree       = NULL;
2759   mesh->getchildsymmetry    = NULL;
2760   mesh->vtkCellHeight       = 0;
2761   mesh->useAnchors          = PETSC_FALSE;
2762 
2763   mesh->maxProjectionHeight = 0;
2764 
2765   mesh->neighbors           = NULL;
2766 
2767   mesh->printSetValues = PETSC_FALSE;
2768   mesh->printFEM       = 0;
2769   mesh->printTol       = 1.0e-10;
2770 
2771   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
2772   PetscFunctionReturn(0);
2773 }
2774 
2775 /*@
2776   DMPlexCreate - Creates a DMPlex object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
2777 
2778   Collective
2779 
2780   Input Parameter:
2781 . comm - The communicator for the DMPlex object
2782 
2783   Output Parameter:
2784 . mesh  - The DMPlex object
2785 
2786   Level: beginner
2787 
2788 @*/
2789 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
2790 {
2791   PetscErrorCode ierr;
2792 
2793   PetscFunctionBegin;
2794   PetscValidPointer(mesh,2);
2795   ierr = DMCreate(comm, mesh);CHKERRQ(ierr);
2796   ierr = DMSetType(*mesh, DMPLEX);CHKERRQ(ierr);
2797   PetscFunctionReturn(0);
2798 }
2799 
2800 /*@C
2801   DMPlexBuildFromCellListParallel - Build distributed DMPLEX topology from a list of vertices for each cell (common mesh generator output)
2802 
2803   Input Parameters:
2804 + dm - The DM
2805 . numCells - The number of cells owned by this process
2806 . numVertices - The number of vertices owned by this process, or PETSC_DECIDE
2807 . NVertices - The global number of vertices, or PETSC_DECIDE
2808 . numCorners - The number of vertices for each cell
2809 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
2810 
2811   Output Parameter:
2812 . vertexSF - (Optional) SF describing complete vertex ownership
2813 
2814   Notes:
2815   Two triangles sharing a face
2816 $
2817 $        2
2818 $      / | \
2819 $     /  |  \
2820 $    /   |   \
2821 $   0  0 | 1  3
2822 $    \   |   /
2823 $     \  |  /
2824 $      \ | /
2825 $        1
2826 would have input
2827 $  numCells = 2, numVertices = 4
2828 $  cells = [0 1 2  1 3 2]
2829 $
2830 which would result in the DMPlex
2831 $
2832 $        4
2833 $      / | \
2834 $     /  |  \
2835 $    /   |   \
2836 $   2  0 | 1  5
2837 $    \   |   /
2838 $     \  |  /
2839 $      \ | /
2840 $        3
2841 
2842   Vertices are implicitly numbered consecutively 0,...,NVertices.
2843   Each rank owns a chunk of numVertices consecutive vertices.
2844   If numVertices is PETSC_DECIDE, PETSc will distribute them as evenly as possible using PetscLayout.
2845   If both NVertices and numVertices are PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
2846   If only NVertices is PETSC_DECIDE, it is computed as the sum of numVertices over all ranks.
2847 
2848   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
2849 
2850   Not currently supported in Fortran.
2851 
2852   Level: advanced
2853 
2854 .seealso: DMPlexBuildFromCellList(), DMPlexCreateFromCellListParallelPetsc(), DMPlexBuildCoordinatesFromCellListParallel()
2855 @*/
2856 PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PetscSF *vertexSF)
2857 {
2858   PetscSF         sfPoint, sfVert;
2859   PetscLayout     vLayout;
2860   PetscHSetI      vhash;
2861   PetscSFNode    *remoteVerticesAdj, *vertexLocal, *vertexOwner, *remoteVertex;
2862   const PetscInt *vrange;
2863   PetscInt        numVerticesAdj, off = 0, *verticesAdj, numVerticesGhost = 0, *localVertex, *cones, c, p, v, g, dim;
2864   PetscMPIInt     rank, size;
2865   PetscErrorCode  ierr;
2866 
2867   PetscFunctionBegin;
2868   PetscValidLogicalCollectiveInt(dm,NVertices,4);
2869   ierr = PetscLogEventBegin(DMPLEX_BuildFromCellList,dm,0,0,0);CHKERRQ(ierr);
2870   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2871   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2872   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
2873   /* Get/check global number of vertices */
2874   {
2875     PetscInt NVerticesInCells, i;
2876     const PetscInt len = numCells * numCorners;
2877 
2878     /* NVerticesInCells = max(cells) + 1 */
2879     NVerticesInCells = PETSC_MIN_INT;
2880     for (i=0; i<len; i++) if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
2881     ++NVerticesInCells;
2882     ierr = MPI_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
2883 
2884     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
2885     else if (NVertices != PETSC_DECIDE && NVertices < NVerticesInCells) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %D must be greater than or equal to the number of vertices in cells %D",NVertices,NVerticesInCells);
2886   }
2887   /* Partition vertices */
2888   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) dm), &vLayout);CHKERRQ(ierr);
2889   ierr = PetscLayoutSetLocalSize(vLayout, numVertices);CHKERRQ(ierr);
2890   ierr = PetscLayoutSetSize(vLayout, NVertices);CHKERRQ(ierr);
2891   ierr = PetscLayoutSetBlockSize(vLayout, 1);CHKERRQ(ierr);
2892   ierr = PetscLayoutSetUp(vLayout);CHKERRQ(ierr);
2893   ierr = PetscLayoutGetRanges(vLayout, &vrange);CHKERRQ(ierr);
2894   /* Count vertices and map them to procs */
2895   ierr = PetscHSetICreate(&vhash);CHKERRQ(ierr);
2896   for (c = 0; c < numCells; ++c) {
2897     for (p = 0; p < numCorners; ++p) {
2898       ierr = PetscHSetIAdd(vhash, cells[c*numCorners+p]);CHKERRQ(ierr);
2899     }
2900   }
2901   ierr = PetscHSetIGetSize(vhash, &numVerticesAdj);CHKERRQ(ierr);
2902   ierr = PetscMalloc1(numVerticesAdj, &verticesAdj);CHKERRQ(ierr);
2903   ierr = PetscHSetIGetElems(vhash, &off, verticesAdj);CHKERRQ(ierr);
2904   ierr = PetscHSetIDestroy(&vhash);CHKERRQ(ierr);
2905   if (off != numVerticesAdj) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %D should be %D", off, numVerticesAdj);
2906   ierr = PetscSortInt(numVerticesAdj, verticesAdj);CHKERRQ(ierr);
2907   ierr = PetscMalloc1(numVerticesAdj, &remoteVerticesAdj);CHKERRQ(ierr);
2908   for (v = 0; v < numVerticesAdj; ++v) {
2909     const PetscInt gv = verticesAdj[v];
2910     PetscInt       vrank;
2911 
2912     ierr = PetscFindInt(gv, size+1, vrange, &vrank);CHKERRQ(ierr);
2913     vrank = vrank < 0 ? -(vrank+2) : vrank;
2914     remoteVerticesAdj[v].index = gv - vrange[vrank];
2915     remoteVerticesAdj[v].rank  = vrank;
2916   }
2917   /* Create cones */
2918   ierr = DMPlexSetChart(dm, 0, numCells+numVerticesAdj);CHKERRQ(ierr);
2919   for (c = 0; c < numCells; ++c) {ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);}
2920   ierr = DMSetUp(dm);CHKERRQ(ierr);
2921   ierr = DMPlexGetCones(dm,&cones);CHKERRQ(ierr);
2922   for (c = 0; c < numCells; ++c) {
2923     for (p = 0; p < numCorners; ++p) {
2924       const PetscInt gv = cells[c*numCorners+p];
2925       PetscInt       lv;
2926 
2927       ierr = PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv);CHKERRQ(ierr);
2928       if (lv < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %D in local connectivity", gv);
2929       cones[c*numCorners+p] = lv+numCells;
2930     }
2931   }
2932   /* Create SF for vertices */
2933   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), &sfVert);CHKERRQ(ierr);
2934   ierr = PetscObjectSetName((PetscObject) sfVert, "Vertex Ownership SF");CHKERRQ(ierr);
2935   ierr = PetscSFSetFromOptions(sfVert);CHKERRQ(ierr);
2936   ierr = PetscSFSetGraph(sfVert, numVertices, numVerticesAdj, NULL, PETSC_OWN_POINTER, remoteVerticesAdj, PETSC_OWN_POINTER);CHKERRQ(ierr);
2937   ierr = PetscFree(verticesAdj);CHKERRQ(ierr);
2938   /* Build pointSF */
2939   ierr = PetscMalloc2(numVerticesAdj, &vertexLocal, numVertices, &vertexOwner);CHKERRQ(ierr);
2940   for (v = 0; v < numVerticesAdj; ++v) {vertexLocal[v].index = v+numCells; vertexLocal[v].rank = rank;}
2941   for (v = 0; v < numVertices;    ++v) {vertexOwner[v].index = -1;         vertexOwner[v].rank = -1;}
2942   ierr = PetscSFReduceBegin(sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2943   ierr = PetscSFReduceEnd(sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2944   for (v = 0; v < numVertices;    ++v) if (vertexOwner[v].rank < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global vertex %D on rank %d was unclaimed", v + vrange[rank], rank);
2945   ierr = PetscSFBcastBegin(sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2946   ierr = PetscSFBcastEnd(sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2947   for (v = 0; v < numVerticesAdj; ++v) if (vertexLocal[v].rank != rank) ++numVerticesGhost;
2948   ierr = PetscMalloc1(numVerticesGhost, &localVertex);CHKERRQ(ierr);
2949   ierr = PetscMalloc1(numVerticesGhost, &remoteVertex);CHKERRQ(ierr);
2950   for (v = 0, g = 0; v < numVerticesAdj; ++v) {
2951     if (vertexLocal[v].rank != rank) {
2952       localVertex[g]        = v+numCells;
2953       remoteVertex[g].index = vertexLocal[v].index;
2954       remoteVertex[g].rank  = vertexLocal[v].rank;
2955       ++g;
2956     }
2957   }
2958   ierr = PetscFree2(vertexLocal, vertexOwner);CHKERRQ(ierr);
2959   if (g != numVerticesGhost) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of vertex ghosts %D should be %D", g, numVerticesGhost);
2960   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
2961   ierr = PetscObjectSetName((PetscObject) sfPoint, "point SF");CHKERRQ(ierr);
2962   ierr = PetscSFSetGraph(sfPoint, numCells+numVerticesAdj, numVerticesGhost, localVertex, PETSC_OWN_POINTER, remoteVertex, PETSC_OWN_POINTER);CHKERRQ(ierr);
2963   ierr = PetscLayoutDestroy(&vLayout);CHKERRQ(ierr);
2964   /* Fill in the rest of the topology structure */
2965   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2966   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2967   ierr = PetscLogEventEnd(DMPLEX_BuildFromCellList,dm,0,0,0);CHKERRQ(ierr);
2968   if (vertexSF) *vertexSF = sfVert;
2969   else {ierr = PetscSFDestroy(&sfVert);CHKERRQ(ierr);}
2970   PetscFunctionReturn(0);
2971 }
2972 
2973 /*@C
2974   DMPlexBuildCoordinatesFromCellListParallel - Build DM coordinates from a list of coordinates for each owned vertex (common mesh generator output)
2975 
2976   Input Parameters:
2977 + dm - The DM
2978 . spaceDim - The spatial dimension used for coordinates
2979 . sfVert - SF describing complete vertex ownership
2980 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
2981 
2982   Level: advanced
2983 
2984   Notes:
2985   Not currently supported in Fortran.
2986 
2987 .seealso: DMPlexBuildCoordinatesFromCellList(), DMPlexCreateFromCellListParallelPetsc(), DMPlexBuildFromCellListParallel()
2988 @*/
2989 PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
2990 {
2991   PetscSection   coordSection;
2992   Vec            coordinates;
2993   PetscScalar   *coords;
2994   PetscInt       numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;
2995   PetscErrorCode ierr;
2996 
2997   PetscFunctionBegin;
2998   ierr = PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList,dm,0,0,0);CHKERRQ(ierr);
2999   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3000   if (vStart < 0 || vEnd < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
3001   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
3002   ierr = PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL);CHKERRQ(ierr);
3003   if (vEnd - vStart != numVerticesAdj) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Supplied sfVert has wrong number of leaves = %D != %D = vEnd - vStart",numVerticesAdj,vEnd - vStart);
3004   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3005   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3006   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
3007   ierr = PetscSectionSetChart(coordSection, vStart, vEnd);CHKERRQ(ierr);
3008   for (v = vStart; v < vEnd; ++v) {
3009     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
3010     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
3011   }
3012   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3013   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
3014   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
3015   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
3016   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3017   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3018   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
3019   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3020   {
3021     MPI_Datatype coordtype;
3022 
3023     /* Need a temp buffer for coords if we have complex/single */
3024     ierr = MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype);CHKERRQ(ierr);
3025     ierr = MPI_Type_commit(&coordtype);CHKERRQ(ierr);
3026 #if defined(PETSC_USE_COMPLEX)
3027     {
3028     PetscScalar *svertexCoords;
3029     PetscInt    i;
3030     ierr = PetscMalloc1(numVertices*spaceDim,&svertexCoords);CHKERRQ(ierr);
3031     for (i=0; i<numVertices*spaceDim; i++) svertexCoords[i] = vertexCoords[i];
3032     ierr = PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
3033     ierr = PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
3034     ierr = PetscFree(svertexCoords);CHKERRQ(ierr);
3035     }
3036 #else
3037     ierr = PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
3038     ierr = PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
3039 #endif
3040     ierr = MPI_Type_free(&coordtype);CHKERRQ(ierr);
3041   }
3042   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3043   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
3044   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3045   ierr = PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList,dm,0,0,0);CHKERRQ(ierr);
3046   PetscFunctionReturn(0);
3047 }
3048 
3049 /*@
3050   DMPlexCreateFromCellListParallelPetsc - Create distributed DMPLEX from a list of vertices for each cell (common mesh generator output)
3051 
3052   Input Parameters:
3053 + comm - The communicator
3054 . dim - The topological dimension of the mesh
3055 . numCells - The number of cells owned by this process
3056 . numVertices - The number of vertices owned by this process, or PETSC_DECIDE
3057 . NVertices - The global number of vertices, or PETSC_DECIDE
3058 . numCorners - The number of vertices for each cell
3059 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
3060 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
3061 . spaceDim - The spatial dimension used for coordinates
3062 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
3063 
3064   Output Parameter:
3065 + dm - The DM
3066 - vertexSF - (Optional) SF describing complete vertex ownership
3067 
3068   Notes:
3069   This function is just a convenient sequence of DMCreate(), DMSetType(), DMSetDimension(),
3070   DMPlexBuildFromCellListParallel(), DMPlexInterpolate(), DMPlexBuildCoordinatesFromCellListParallel()
3071 
3072   See DMPlexBuildFromCellListParallel() for an example and details about the topology-related parameters.
3073   See DMPlexBuildCoordinatesFromCellListParallel() for details about the geometry-related parameters.
3074 
3075   Level: intermediate
3076 
3077 .seealso: DMPlexCreateFromCellListPetsc(), DMPlexBuildFromCellListParallel(), DMPlexBuildCoordinatesFromCellListParallel(), DMPlexCreateFromDAG(), DMPlexCreate()
3078 @*/
3079 PetscErrorCode DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PetscSF *vertexSF, DM *dm)
3080 {
3081   PetscSF        sfVert;
3082   PetscErrorCode ierr;
3083 
3084   PetscFunctionBegin;
3085   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3086   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3087   PetscValidLogicalCollectiveInt(*dm, dim, 2);
3088   PetscValidLogicalCollectiveInt(*dm, spaceDim, 8);
3089   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
3090   ierr = DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert);CHKERRQ(ierr);
3091   if (interpolate) {
3092     DM idm;
3093 
3094     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3095     ierr = DMDestroy(dm);CHKERRQ(ierr);
3096     *dm  = idm;
3097   }
3098   ierr = DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords);CHKERRQ(ierr);
3099   if (vertexSF) *vertexSF = sfVert;
3100   else {ierr = PetscSFDestroy(&sfVert);CHKERRQ(ierr);}
3101   PetscFunctionReturn(0);
3102 }
3103 
3104 
3105 /*@
3106   DMPlexCreateFromCellListParallel - Deprecated, use DMPlexCreateFromCellListParallelPetsc()
3107 
3108   Level: deprecated
3109 
3110 .seealso: DMPlexCreateFromCellListParallelPetsc()
3111 @*/
3112 PetscErrorCode DMPlexCreateFromCellListParallel(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PetscSF *vertexSF, DM *dm)
3113 {
3114   PetscErrorCode ierr;
3115   PetscInt       i;
3116   PetscInt       *pintCells;
3117 
3118   PetscFunctionBegin;
3119   if (sizeof(int) > sizeof(PetscInt)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Size of int %zd greater than size of PetscInt %zd. Reconfigure PETSc --with-64-bit-indices=1", sizeof(int), sizeof(PetscInt));
3120   if (sizeof(int) == sizeof(PetscInt)) {
3121     pintCells = (PetscInt *) cells;
3122   } else {
3123     ierr = PetscMalloc1(numCells*numCorners, &pintCells);CHKERRQ(ierr);
3124     for (i = 0; i < numCells*numCorners; i++) {
3125       pintCells[i] = (PetscInt) cells[i];
3126     }
3127   }
3128   ierr = DMPlexCreateFromCellListParallelPetsc(comm, dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, pintCells, spaceDim, vertexCoords, vertexSF, dm);CHKERRQ(ierr);
3129   if (sizeof(int) != sizeof(PetscInt)) {
3130     ierr = PetscFree(pintCells);CHKERRQ(ierr);
3131   }
3132   PetscFunctionReturn(0);
3133 }
3134 
3135 /*@C
3136   DMPlexBuildFromCellList - Build DMPLEX topology from a list of vertices for each cell (common mesh generator output)
3137 
3138   Input Parameters:
3139 + dm - The DM
3140 . numCells - The number of cells owned by this process
3141 . numVertices - The number of vertices owned by this process, or PETSC_DECIDE
3142 . numCorners - The number of vertices for each cell
3143 - cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
3144 
3145   Level: advanced
3146 
3147   Notes:
3148   Two triangles sharing a face
3149 $
3150 $        2
3151 $      / | \
3152 $     /  |  \
3153 $    /   |   \
3154 $   0  0 | 1  3
3155 $    \   |   /
3156 $     \  |  /
3157 $      \ | /
3158 $        1
3159 would have input
3160 $  numCells = 2, numVertices = 4
3161 $  cells = [0 1 2  1 3 2]
3162 $
3163 which would result in the DMPlex
3164 $
3165 $        4
3166 $      / | \
3167 $     /  |  \
3168 $    /   |   \
3169 $   2  0 | 1  5
3170 $    \   |   /
3171 $     \  |  /
3172 $      \ | /
3173 $        3
3174 
3175   If numVertices is PETSC_DECIDE, it is computed by PETSc as the maximum vertex index in cells + 1.
3176 
3177   Not currently supported in Fortran.
3178 
3179 .seealso: DMPlexBuildFromCellListParallel(), DMPlexBuildCoordinatesFromCellList(), DMPlexCreateFromCellListPetsc()
3180 @*/
3181 PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
3182 {
3183   PetscInt      *cones, c, p, dim;
3184   PetscErrorCode ierr;
3185 
3186   PetscFunctionBegin;
3187   ierr = PetscLogEventBegin(DMPLEX_BuildFromCellList,dm,0,0,0);CHKERRQ(ierr);
3188   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3189   /* Get/check global number of vertices */
3190   {
3191     PetscInt NVerticesInCells, i;
3192     const PetscInt len = numCells * numCorners;
3193 
3194     /* NVerticesInCells = max(cells) + 1 */
3195     NVerticesInCells = PETSC_MIN_INT;
3196     for (i=0; i<len; i++) if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
3197     ++NVerticesInCells;
3198 
3199     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
3200     else if (numVertices < NVerticesInCells) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Specified number of vertices %D must be greater than or equal to the number of vertices in cells %D",numVertices,NVerticesInCells);
3201   }
3202   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
3203   for (c = 0; c < numCells; ++c) {
3204     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
3205   }
3206   ierr = DMSetUp(dm);CHKERRQ(ierr);
3207   ierr = DMPlexGetCones(dm,&cones);CHKERRQ(ierr);
3208   for (c = 0; c < numCells; ++c) {
3209     for (p = 0; p < numCorners; ++p) {
3210       cones[c*numCorners+p] = cells[c*numCorners+p]+numCells;
3211     }
3212   }
3213   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
3214   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
3215   ierr = PetscLogEventEnd(DMPLEX_BuildFromCellList,dm,0,0,0);CHKERRQ(ierr);
3216   PetscFunctionReturn(0);
3217 }
3218 
3219 /*@C
3220   DMPlexBuildCoordinatesFromCellList - Build DM coordinates from a list of coordinates for each owned vertex (common mesh generator output)
3221 
3222   Input Parameters:
3223 + dm - The DM
3224 . spaceDim - The spatial dimension used for coordinates
3225 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
3226 
3227   Level: advanced
3228 
3229   Notes:
3230   Not currently supported in Fortran.
3231 
3232 .seealso: DMPlexBuildCoordinatesFromCellListParallel(), DMPlexCreateFromCellListPetsc(), DMPlexBuildFromCellList()
3233 @*/
3234 PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
3235 {
3236   PetscSection   coordSection;
3237   Vec            coordinates;
3238   DM             cdm;
3239   PetscScalar   *coords;
3240   PetscInt       v, vStart, vEnd, d;
3241   PetscErrorCode ierr;
3242 
3243   PetscFunctionBegin;
3244   ierr = PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList,dm,0,0,0);CHKERRQ(ierr);
3245   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3246   if (vStart < 0 || vEnd < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
3247   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
3248   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3249   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3250   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
3251   ierr = PetscSectionSetChart(coordSection, vStart, vEnd);CHKERRQ(ierr);
3252   for (v = vStart; v < vEnd; ++v) {
3253     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
3254     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
3255   }
3256   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3257 
3258   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3259   ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
3260   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
3261   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3262   ierr = VecGetArrayWrite(coordinates, &coords);CHKERRQ(ierr);
3263   for (v = 0; v < vEnd-vStart; ++v) {
3264     for (d = 0; d < spaceDim; ++d) {
3265       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
3266     }
3267   }
3268   ierr = VecRestoreArrayWrite(coordinates, &coords);CHKERRQ(ierr);
3269   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
3270   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3271   ierr = PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList,dm,0,0,0);CHKERRQ(ierr);
3272   PetscFunctionReturn(0);
3273 }
3274 
3275 /*@
3276   DMPlexCreateFromCellListPetsc - Create DMPLEX from a list of vertices for each cell (common mesh generator output)
3277 
3278   Input Parameters:
3279 + comm - The communicator
3280 . dim - The topological dimension of the mesh
3281 . numCells - The number of cells
3282 . numVertices - The number of vertices owned by this process, or PETSC_DECIDE
3283 . numCorners - The number of vertices for each cell
3284 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
3285 . cells - An array of numCells*numCorners numbers, the vertices for each cell
3286 . spaceDim - The spatial dimension used for coordinates
3287 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
3288 
3289   Output Parameter:
3290 . dm - The DM
3291 
3292   Notes:
3293   This function is just a convenient sequence of DMCreate(), DMSetType(), DMSetDimension(), DMPlexBuildFromCellList(),
3294   DMPlexInterpolate(), DMPlexBuildCoordinatesFromCellList()
3295 
3296   See DMPlexBuildFromCellList() for an example and details about the topology-related parameters.
3297   See DMPlexBuildCoordinatesFromCellList() for details about the geometry-related parameters.
3298 
3299   Level: intermediate
3300 
3301 .seealso: DMPlexCreateFromCellListParallelPetsc(), DMPlexBuildFromCellList(), DMPlexBuildCoordinatesFromCellList(), DMPlexCreateFromDAG(), DMPlexCreate()
3302 @*/
3303 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)
3304 {
3305   PetscErrorCode ierr;
3306 
3307   PetscFunctionBegin;
3308   if (!dim) SETERRQ(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.");
3309   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3310   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3311   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
3312   ierr = DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
3313   if (interpolate) {
3314     DM idm;
3315 
3316     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3317     ierr = DMDestroy(dm);CHKERRQ(ierr);
3318     *dm  = idm;
3319   }
3320   ierr = DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords);CHKERRQ(ierr);
3321   PetscFunctionReturn(0);
3322 }
3323 
3324 /*@
3325   DMPlexCreateFromCellList - Deprecated, use DMPlexCreateFromCellListPetsc()
3326 
3327   Level: deprecated
3328 
3329 .seealso: DMPlexCreateFromCellListPetsc()
3330 @*/
3331 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], PetscInt spaceDim, const double vertexCoords[], DM *dm)
3332 {
3333   PetscErrorCode ierr;
3334   PetscInt       i;
3335   PetscInt       *pintCells;
3336   PetscReal      *prealVC;
3337 
3338   PetscFunctionBegin;
3339   if (sizeof(int) > sizeof(PetscInt)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Size of int %zd greater than size of PetscInt %zd. Reconfigure PETSc --with-64-bit-indices=1", sizeof(int), sizeof(PetscInt));
3340   if (sizeof(int) == sizeof(PetscInt)) {
3341     pintCells = (PetscInt *) cells;
3342   } else {
3343     ierr = PetscMalloc1(numCells*numCorners, &pintCells);CHKERRQ(ierr);
3344     for (i = 0; i < numCells*numCorners; i++) {
3345       pintCells[i] = (PetscInt) cells[i];
3346     }
3347   }
3348   if (sizeof(double) > sizeof(PetscReal)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Size of double %zd greater than size of PetscReal %zd. Reconfigure PETSc --with-precision=<higher precision>.", sizeof(double), sizeof(PetscReal));
3349   if (sizeof(double) == sizeof(PetscReal)) {
3350     prealVC = (PetscReal *) vertexCoords;
3351   } else {
3352     ierr = PetscMalloc1(numVertices*spaceDim, &prealVC);CHKERRQ(ierr);
3353     for (i = 0; i < numVertices*spaceDim; i++) {
3354       prealVC[i] = (PetscReal) vertexCoords[i];
3355     }
3356   }
3357   ierr = DMPlexCreateFromCellListPetsc(comm, dim, numCells, numVertices, numCorners, interpolate, pintCells, spaceDim, prealVC, dm);CHKERRQ(ierr);
3358   if (sizeof(int) != sizeof(PetscInt)) {
3359     ierr = PetscFree(pintCells);CHKERRQ(ierr);
3360   }
3361   if (sizeof(double) != sizeof(PetscReal)) {
3362     ierr = PetscFree(prealVC);CHKERRQ(ierr);
3363   }
3364   PetscFunctionReturn(0);
3365 }
3366 
3367 /*@
3368   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a DM
3369 
3370   Input Parameters:
3371 + dm - The empty DM object, usually from DMCreate() and DMSetDimension()
3372 . depth - The depth of the DAG
3373 . numPoints - Array of size depth + 1 containing the number of points at each depth
3374 . coneSize - The cone size of each point
3375 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
3376 . coneOrientations - The orientation of each cone point
3377 - vertexCoords - An array of numPoints[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via DMSetCoordinateDim()
3378 
3379   Output Parameter:
3380 . dm - The DM
3381 
3382   Note: Two triangles sharing a face would have input
3383 $  depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
3384 $  cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
3385 $ vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
3386 $
3387 which would result in the DMPlex
3388 $
3389 $        4
3390 $      / | \
3391 $     /  |  \
3392 $    /   |   \
3393 $   2  0 | 1  5
3394 $    \   |   /
3395 $     \  |  /
3396 $      \ | /
3397 $        3
3398 $
3399 $ Notice that all points are numbered consecutively, unlike DMPlexCreateFromCellListPetsc()
3400 
3401   Level: advanced
3402 
3403 .seealso: DMPlexCreateFromCellListPetsc(), DMPlexCreate()
3404 @*/
3405 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
3406 {
3407   Vec            coordinates;
3408   PetscSection   coordSection;
3409   PetscScalar    *coords;
3410   PetscInt       coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
3411   PetscErrorCode ierr;
3412 
3413   PetscFunctionBegin;
3414   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3415   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
3416   if (dimEmbed < dim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Embedding dimension %D cannot be less than intrinsic dimension %d",dimEmbed,dim);
3417   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
3418   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
3419   for (p = pStart; p < pEnd; ++p) {
3420     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
3421     if (firstVertex < 0 && !coneSize[p - pStart]) {
3422       firstVertex = p - pStart;
3423     }
3424   }
3425   if (firstVertex < 0 && numPoints[0]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected %D vertices but could not find any", numPoints[0]);
3426   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
3427   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
3428     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
3429     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
3430   }
3431   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
3432   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
3433   /* Build coordinates */
3434   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3435   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3436   ierr = PetscSectionSetFieldComponents(coordSection, 0, dimEmbed);CHKERRQ(ierr);
3437   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
3438   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
3439     ierr = PetscSectionSetDof(coordSection, v, dimEmbed);CHKERRQ(ierr);
3440     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed);CHKERRQ(ierr);
3441   }
3442   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3443   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
3444   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
3445   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3446   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3447   ierr = VecSetBlockSize(coordinates, dimEmbed);CHKERRQ(ierr);
3448   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
3449   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3450   for (v = 0; v < numPoints[0]; ++v) {
3451     PetscInt off;
3452 
3453     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
3454     for (d = 0; d < dimEmbed; ++d) {
3455       coords[off+d] = vertexCoords[v*dimEmbed+d];
3456     }
3457   }
3458   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3459   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
3460   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 /*@C
3465   DMPlexCreateCellVertexFromFile - Create a DMPlex mesh from a simple cell-vertex file.
3466 
3467 + comm        - The MPI communicator
3468 . filename    - Name of the .dat file
3469 - interpolate - Create faces and edges in the mesh
3470 
3471   Output Parameter:
3472 . dm  - The DM object representing the mesh
3473 
3474   Note: The format is the simplest possible:
3475 $ Ne
3476 $ v0 v1 ... vk
3477 $ Nv
3478 $ x y z marker
3479 
3480   Level: beginner
3481 
3482 .seealso: DMPlexCreateFromFile(), DMPlexCreateMedFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
3483 @*/
3484 PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
3485 {
3486   DMLabel         marker;
3487   PetscViewer     viewer;
3488   Vec             coordinates;
3489   PetscSection    coordSection;
3490   PetscScalar    *coords;
3491   char            line[PETSC_MAX_PATH_LEN];
3492   PetscInt        dim = 3, cdim = 3, coordSize, v, c, d;
3493   PetscMPIInt     rank;
3494   int             snum, Nv, Nc;
3495   PetscErrorCode  ierr;
3496 
3497   PetscFunctionBegin;
3498   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3499   ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
3500   ierr = PetscViewerSetType(viewer, PETSCVIEWERASCII);CHKERRQ(ierr);
3501   ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
3502   ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
3503   if (!rank) {
3504     ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
3505     snum = sscanf(line, "%d %d", &Nc, &Nv);
3506     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3507   } else {
3508     Nc = Nv = 0;
3509   }
3510   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3511   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3512   ierr = DMPlexSetChart(*dm, 0, Nc+Nv);CHKERRQ(ierr);
3513   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
3514   ierr = DMSetCoordinateDim(*dm, cdim);CHKERRQ(ierr);
3515   /* Read topology */
3516   if (!rank) {
3517     PetscInt cone[8], corners = 8;
3518     int      vbuf[8], v;
3519 
3520     for (c = 0; c < Nc; ++c) {ierr = DMPlexSetConeSize(*dm, c, corners);CHKERRQ(ierr);}
3521     ierr = DMSetUp(*dm);CHKERRQ(ierr);
3522     for (c = 0; c < Nc; ++c) {
3523       ierr = PetscViewerRead(viewer, line, corners, NULL, PETSC_STRING);CHKERRQ(ierr);
3524       snum = sscanf(line, "%d %d %d %d %d %d %d %d", &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
3525       if (snum != corners) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3526       for (v = 0; v < corners; ++v) cone[v] = vbuf[v] + Nc;
3527       /* Hexahedra are inverted */
3528       {
3529         PetscInt tmp = cone[1];
3530         cone[1] = cone[3];
3531         cone[3] = tmp;
3532       }
3533       ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
3534     }
3535   }
3536   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
3537   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
3538   /* Read coordinates */
3539   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
3540   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3541   ierr = PetscSectionSetFieldComponents(coordSection, 0, cdim);CHKERRQ(ierr);
3542   ierr = PetscSectionSetChart(coordSection, Nc, Nc + Nv);CHKERRQ(ierr);
3543   for (v = Nc; v < Nc+Nv; ++v) {
3544     ierr = PetscSectionSetDof(coordSection, v, cdim);CHKERRQ(ierr);
3545     ierr = PetscSectionSetFieldDof(coordSection, v, 0, cdim);CHKERRQ(ierr);
3546   }
3547   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3548   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
3549   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
3550   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3551   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3552   ierr = VecSetBlockSize(coordinates, cdim);CHKERRQ(ierr);
3553   ierr = VecSetType(coordinates, VECSTANDARD);CHKERRQ(ierr);
3554   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3555   if (!rank) {
3556     double x[3];
3557     int    val;
3558 
3559     ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
3560     ierr = DMGetLabel(*dm, "marker", &marker);CHKERRQ(ierr);
3561     for (v = 0; v < Nv; ++v) {
3562       ierr = PetscViewerRead(viewer, line, 4, NULL, PETSC_STRING);CHKERRQ(ierr);
3563       snum = sscanf(line, "%lg %lg %lg %d", &x[0], &x[1], &x[2], &val);
3564       if (snum != 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3565       for (d = 0; d < cdim; ++d) coords[v*cdim+d] = x[d];
3566       if (val) {ierr = DMLabelSetValue(marker, v+Nc, val);CHKERRQ(ierr);}
3567     }
3568   }
3569   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3570   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
3571   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3572   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
3573   if (interpolate) {
3574     DM      idm;
3575     DMLabel bdlabel;
3576 
3577     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3578     ierr = DMDestroy(dm);CHKERRQ(ierr);
3579     *dm  = idm;
3580 
3581     ierr = DMGetLabel(*dm, "marker", &bdlabel);CHKERRQ(ierr);
3582     ierr = DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel);CHKERRQ(ierr);
3583     ierr = DMPlexLabelComplete(*dm, bdlabel);CHKERRQ(ierr);
3584   }
3585   PetscFunctionReturn(0);
3586 }
3587 
3588 /*@C
3589   DMPlexCreateFromFile - This takes a filename and produces a DM
3590 
3591   Input Parameters:
3592 + comm - The communicator
3593 . filename - A file name
3594 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
3595 
3596   Output Parameter:
3597 . dm - The DM
3598 
3599   Options Database Keys:
3600 . -dm_plex_create_from_hdf5_xdmf - use the PETSC_VIEWER_HDF5_XDMF format for reading HDF5
3601 
3602   Use -dm_plex_create_ prefix to pass options to the internal PetscViewer, e.g.
3603 $ -dm_plex_create_viewer_hdf5_collective
3604 
3605   Level: beginner
3606 
3607 .seealso: DMPlexCreateFromDAG(), DMPlexCreateFromCellListPetsc(), DMPlexCreate()
3608 @*/
3609 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
3610 {
3611   const char    *extGmsh    = ".msh";
3612   const char    *extGmsh2   = ".msh2";
3613   const char    *extGmsh4   = ".msh4";
3614   const char    *extCGNS    = ".cgns";
3615   const char    *extExodus  = ".exo";
3616   const char    *extGenesis = ".gen";
3617   const char    *extFluent  = ".cas";
3618   const char    *extHDF5    = ".h5";
3619   const char    *extMed     = ".med";
3620   const char    *extPLY     = ".ply";
3621   const char    *extCV      = ".dat";
3622   size_t         len;
3623   PetscBool      isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isMed, isPLY, isCV;
3624   PetscMPIInt    rank;
3625   PetscErrorCode ierr;
3626 
3627   PetscFunctionBegin;
3628   PetscValidCharPointer(filename, 2);
3629   PetscValidPointer(dm, 4);
3630   ierr = DMInitializePackage();CHKERRQ(ierr);
3631   ierr = PetscLogEventBegin(DMPLEX_CreateFromFile,0,0,0,0);CHKERRQ(ierr);
3632   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3633   ierr = PetscStrlen(filename, &len);CHKERRQ(ierr);
3634   if (!len) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
3635   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGmsh,    4, &isGmsh);CHKERRQ(ierr);
3636   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extGmsh2,   5, &isGmsh2);CHKERRQ(ierr);
3637   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extGmsh4,   5, &isGmsh4);CHKERRQ(ierr);
3638   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extCGNS,    5, &isCGNS);CHKERRQ(ierr);
3639   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extExodus,  4, &isExodus);CHKERRQ(ierr);
3640   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGenesis, 4, &isGenesis);CHKERRQ(ierr);
3641   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extFluent,  4, &isFluent);CHKERRQ(ierr);
3642   ierr = PetscStrncmp(&filename[PetscMax(0,len-3)], extHDF5,    3, &isHDF5);CHKERRQ(ierr);
3643   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extMed,     4, &isMed);CHKERRQ(ierr);
3644   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extPLY,     4, &isPLY);CHKERRQ(ierr);
3645   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extCV,      4, &isCV);CHKERRQ(ierr);
3646   if (isGmsh || isGmsh2 || isGmsh4) {
3647     ierr = DMPlexCreateGmshFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3648   } else if (isCGNS) {
3649     ierr = DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3650   } else if (isExodus || isGenesis) {
3651     ierr = DMPlexCreateExodusFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3652   } else if (isFluent) {
3653     ierr = DMPlexCreateFluentFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3654   } else if (isHDF5) {
3655     PetscBool      load_hdf5_xdmf = PETSC_FALSE;
3656     PetscViewer viewer;
3657 
3658     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
3659     ierr = PetscStrncmp(&filename[PetscMax(0,len-8)], ".xdmf",  5, &load_hdf5_xdmf);CHKERRQ(ierr);
3660     ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &load_hdf5_xdmf, NULL);CHKERRQ(ierr);
3661     ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
3662     ierr = PetscViewerSetType(viewer, PETSCVIEWERHDF5);CHKERRQ(ierr);
3663     ierr = PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_");CHKERRQ(ierr);
3664     ierr = PetscViewerSetFromOptions(viewer);CHKERRQ(ierr);
3665     ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
3666     ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
3667     ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3668     ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3669     if (load_hdf5_xdmf) {ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF);CHKERRQ(ierr);}
3670     ierr = DMLoad(*dm, viewer);CHKERRQ(ierr);
3671     if (load_hdf5_xdmf) {ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);}
3672     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
3673 
3674     if (interpolate) {
3675       DM idm;
3676 
3677       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3678       ierr = DMDestroy(dm);CHKERRQ(ierr);
3679       *dm  = idm;
3680     }
3681   } else if (isMed) {
3682     ierr = DMPlexCreateMedFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3683   } else if (isPLY) {
3684     ierr = DMPlexCreatePLYFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3685   } else if (isCV) {
3686     ierr = DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3687   } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
3688   ierr = PetscLogEventEnd(DMPLEX_CreateFromFile,0,0,0,0);CHKERRQ(ierr);
3689   PetscFunctionReturn(0);
3690 }
3691 
3692 /*@
3693   DMPlexCreateReferenceCellByType - Create a DMPLEX with the appropriate FEM reference cell
3694 
3695   Collective
3696 
3697   Input Parameters:
3698 + comm - The communicator
3699 - ct   - The cell type of the reference cell
3700 
3701   Output Parameter:
3702 . refdm - The reference cell
3703 
3704   Level: intermediate
3705 
3706 .seealso: DMPlexCreateReferenceCell(), DMPlexCreateBoxMesh()
3707 @*/
3708 PetscErrorCode DMPlexCreateReferenceCellByType(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
3709 {
3710   DM             rdm;
3711   Vec            coords;
3712   PetscErrorCode ierr;
3713 
3714   PetscFunctionBegin;
3715   ierr = DMCreate(comm, &rdm);CHKERRQ(ierr);
3716   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
3717   switch (ct) {
3718     case DM_POLYTOPE_POINT:
3719     {
3720       PetscInt    numPoints[1]        = {1};
3721       PetscInt    coneSize[1]         = {0};
3722       PetscInt    cones[1]            = {0};
3723       PetscInt    coneOrientations[1] = {0};
3724       PetscScalar vertexCoords[1]     = {0.0};
3725 
3726       ierr = DMSetDimension(rdm, 0);CHKERRQ(ierr);
3727       ierr = DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3728     }
3729     break;
3730     case DM_POLYTOPE_SEGMENT:
3731     {
3732       PetscInt    numPoints[2]        = {2, 1};
3733       PetscInt    coneSize[3]         = {2, 0, 0};
3734       PetscInt    cones[2]            = {1, 2};
3735       PetscInt    coneOrientations[2] = {0, 0};
3736       PetscScalar vertexCoords[2]     = {-1.0,  1.0};
3737 
3738       ierr = DMSetDimension(rdm, 1);CHKERRQ(ierr);
3739       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3740     }
3741     break;
3742     case DM_POLYTOPE_TRIANGLE:
3743     {
3744       PetscInt    numPoints[2]        = {3, 1};
3745       PetscInt    coneSize[4]         = {3, 0, 0, 0};
3746       PetscInt    cones[3]            = {1, 2, 3};
3747       PetscInt    coneOrientations[3] = {0, 0, 0};
3748       PetscScalar vertexCoords[6]     = {-1.0, -1.0,  1.0, -1.0,  -1.0, 1.0};
3749 
3750       ierr = DMSetDimension(rdm, 2);CHKERRQ(ierr);
3751       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3752     }
3753     break;
3754     case DM_POLYTOPE_QUADRILATERAL:
3755     {
3756       PetscInt    numPoints[2]        = {4, 1};
3757       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3758       PetscInt    cones[4]            = {1, 2, 3, 4};
3759       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3760       PetscScalar vertexCoords[8]     = {-1.0, -1.0,  1.0, -1.0,  1.0, 1.0,  -1.0, 1.0};
3761 
3762       ierr = DMSetDimension(rdm, 2);CHKERRQ(ierr);
3763       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3764     }
3765     break;
3766     case DM_POLYTOPE_SEG_PRISM_TENSOR:
3767     {
3768       PetscInt    numPoints[2]        = {4, 1};
3769       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3770       PetscInt    cones[4]            = {1, 2, 3, 4};
3771       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3772       PetscScalar vertexCoords[8]     = {-1.0, -1.0,  1.0, -1.0,  -1.0, 1.0,  1.0, 1.0};
3773 
3774       ierr = DMSetDimension(rdm, 2);CHKERRQ(ierr);
3775       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3776     }
3777     break;
3778     case DM_POLYTOPE_TETRAHEDRON:
3779     {
3780       PetscInt    numPoints[2]        = {4, 1};
3781       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3782       PetscInt    cones[4]            = {1, 3, 2, 4};
3783       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3784       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};
3785 
3786       ierr = DMSetDimension(rdm, 3);CHKERRQ(ierr);
3787       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3788     }
3789     break;
3790     case DM_POLYTOPE_HEXAHEDRON:
3791     {
3792       PetscInt    numPoints[2]        = {8, 1};
3793       PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3794       PetscInt    cones[8]            = {1, 4, 3, 2, 5, 6, 7, 8};
3795       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3796       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,
3797                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0, 1.0,  1.0,  -1.0, 1.0,  1.0};
3798 
3799       ierr = DMSetDimension(rdm, 3);CHKERRQ(ierr);
3800       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3801     }
3802     break;
3803     case DM_POLYTOPE_TRI_PRISM:
3804     {
3805       PetscInt    numPoints[2]        = {6, 1};
3806       PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3807       PetscInt    cones[6]            = {1, 3, 2, 4, 5, 6};
3808       PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3809       PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  -1.0, 1.0, -1.0,
3810                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  -1.0, 1.0,  1.0};
3811 
3812       ierr = DMSetDimension(rdm, 3);CHKERRQ(ierr);
3813       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3814     }
3815     break;
3816     case DM_POLYTOPE_TRI_PRISM_TENSOR:
3817     {
3818       PetscInt    numPoints[2]        = {6, 1};
3819       PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
3820       PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
3821       PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
3822       PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  -1.0, 1.0, -1.0,
3823                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  -1.0, 1.0,  1.0};
3824 
3825       ierr = DMSetDimension(rdm, 3);CHKERRQ(ierr);
3826       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3827     }
3828     break;
3829     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
3830     {
3831       PetscInt    numPoints[2]        = {8, 1};
3832       PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3833       PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
3834       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3835       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,
3836                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0, 1.0,  1.0,  -1.0, 1.0,  1.0};
3837 
3838       ierr = DMSetDimension(rdm, 3);CHKERRQ(ierr);
3839       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3840     }
3841     break;
3842     default: SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
3843   }
3844   {
3845     PetscInt Nv, v;
3846 
3847     /* Must create the celltype label here so that we do not automatically try to compute the types */
3848     ierr = DMCreateLabel(rdm, "celltype");CHKERRQ(ierr);
3849     ierr = DMPlexSetCellType(rdm, 0, ct);CHKERRQ(ierr);
3850     ierr = DMPlexGetChart(rdm, NULL, &Nv);CHKERRQ(ierr);
3851     for (v = 1; v < Nv; ++v) {ierr = DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);}
3852   }
3853   ierr = DMPlexInterpolate(rdm, refdm);CHKERRQ(ierr);
3854   if (rdm->coordinateDM) {
3855     DM           ncdm;
3856     PetscSection cs;
3857     PetscInt     pEnd = -1;
3858 
3859     ierr = DMGetLocalSection(rdm->coordinateDM, &cs);CHKERRQ(ierr);
3860     if (cs) {ierr = PetscSectionGetChart(cs, NULL, &pEnd);CHKERRQ(ierr);}
3861     if (pEnd >= 0) {
3862       ierr = DMClone(*refdm, &ncdm);CHKERRQ(ierr);
3863       ierr = DMCopyDisc(rdm->coordinateDM, ncdm);CHKERRQ(ierr);
3864       ierr = DMSetLocalSection(ncdm, cs);CHKERRQ(ierr);
3865       ierr = DMSetCoordinateDM(*refdm, ncdm);CHKERRQ(ierr);
3866       ierr = DMDestroy(&ncdm);CHKERRQ(ierr);
3867     }
3868   }
3869   ierr = DMGetCoordinatesLocal(rdm, &coords);CHKERRQ(ierr);
3870   if (coords) {
3871     ierr = DMSetCoordinatesLocal(*refdm, coords);CHKERRQ(ierr);
3872   } else {
3873     ierr = DMGetCoordinates(rdm, &coords);CHKERRQ(ierr);
3874     if (coords) {ierr = DMSetCoordinates(*refdm, coords);CHKERRQ(ierr);}
3875   }
3876   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
3877   PetscFunctionReturn(0);
3878 }
3879 
3880 /*@
3881   DMPlexCreateReferenceCell - Create a DMPLEX with the appropriate FEM reference cell
3882 
3883   Collective
3884 
3885   Input Parameters:
3886 + comm    - The communicator
3887 . dim     - The spatial dimension
3888 - simplex - Flag for simplex, otherwise use a tensor-product cell
3889 
3890   Output Parameter:
3891 . refdm - The reference cell
3892 
3893   Level: intermediate
3894 
3895 .seealso: DMPlexCreateReferenceCellByType(), DMPlexCreateBoxMesh()
3896 @*/
3897 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *refdm)
3898 {
3899   PetscErrorCode ierr;
3900 
3901   PetscFunctionBeginUser;
3902   switch (dim) {
3903   case 0: ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_POINT, refdm);CHKERRQ(ierr);break;
3904   case 1: ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_SEGMENT, refdm);CHKERRQ(ierr);break;
3905   case 2:
3906     if (simplex) {ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_TRIANGLE, refdm);CHKERRQ(ierr);}
3907     else         {ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_QUADRILATERAL, refdm);CHKERRQ(ierr);}
3908     break;
3909   case 3:
3910     if (simplex) {ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_TETRAHEDRON, refdm);CHKERRQ(ierr);}
3911     else         {ierr = DMPlexCreateReferenceCellByType(comm, DM_POLYTOPE_HEXAHEDRON, refdm);CHKERRQ(ierr);}
3912     break;
3913   default:
3914     SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Cannot create reference cell for dimension %D", dim);
3915   }
3916   PetscFunctionReturn(0);
3917 }
3918