xref: /petsc/src/dm/impls/plex/plexcreate.c (revision efe49d75eabee2465aff8c8b4563aca59a954a8b)
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 static PetscLogEvent DM_Plex_CreateFromFile = 0, DM_Plex_CreateFromCellList = 0, DM_Plex_CreateFromCellList_Coordinates = 0;
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 - edges - The number of cells in each direction
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 + -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box
1006 - -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box
1007 
1008   Note: Here is the numbering returned for 2 faces in each direction for tensor cells:
1009 $ 10---17---11---18----12
1010 $  |         |         |
1011 $  |         |         |
1012 $ 20    2   22    3    24
1013 $  |         |         |
1014 $  |         |         |
1015 $  7---15----8---16----9
1016 $  |         |         |
1017 $  |         |         |
1018 $ 19    0   21    1   23
1019 $  |         |         |
1020 $  |         |         |
1021 $  4---13----5---14----6
1022 
1023 and for simplicial cells
1024 
1025 $ 14----8---15----9----16
1026 $  |\     5  |\      7 |
1027 $  | \       | \       |
1028 $ 13   2    14    3    15
1029 $  | 4   \   | 6   \   |
1030 $  |       \ |       \ |
1031 $ 11----6---12----7----13
1032 $  |\        |\        |
1033 $  | \    1  | \     3 |
1034 $ 10   0    11    1    12
1035 $  | 0   \   | 2   \   |
1036 $  |       \ |       \ |
1037 $  8----4----9----5----10
1038 
1039   Level: beginner
1040 
1041 .seealso: DMPlexCreateFromFile(), DMPlexCreateHexCylinderMesh(), DMSetType(), DMCreate()
1042 @*/
1043 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)
1044 {
1045   PetscInt       fac[3] = {0, 0, 0};
1046   PetscReal      low[3] = {0, 0, 0};
1047   PetscReal      upp[3] = {1, 1, 1};
1048   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1049   PetscInt       i, n;
1050   PetscBool      flg;
1051   PetscErrorCode ierr;
1052 
1053   PetscFunctionBegin;
1054   n    = 3;
1055   ierr = PetscOptionsGetIntArray(NULL, NULL, "-dm_plex_box_faces", fac, &n, &flg);CHKERRQ(ierr);
1056   for (i = 0; i < dim; ++i) fac[i] = faces ? faces[i] : (flg && i < n ? fac[i] : (dim == 1 ? 1 : 4-dim));
1057   if (lower) for (i = 0; i < dim; ++i) low[i] = lower[i];
1058   if (upper) for (i = 0; i < dim; ++i) upp[i] = upper[i];
1059   if (periodicity) for (i = 0; i < dim; ++i) bdt[i] = periodicity[i];
1060   /* Allow bounds to be specified from the command line */
1061   n    = 3;
1062   ierr = PetscOptionsGetRealArray(NULL, NULL, "-dm_plex_box_lower", low, &n, &flg);CHKERRQ(ierr);
1063   if (flg && (n != dim)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Lower box point had %D values, should have been %D", n, dim);
1064   n    = 3;
1065   ierr = PetscOptionsGetRealArray(NULL, NULL, "-dm_plex_box_upper", upp, &n, &flg);CHKERRQ(ierr);
1066   if (flg && (n != dim)) SETERRQ2(comm, PETSC_ERR_ARG_SIZ, "Upper box point had %D values, should have been %D", n, dim);
1067 
1068   if (dim == 1)      {ierr = DMPlexCreateLineMesh_Internal(comm, fac[0], low[0], upp[0], bdt[0], dm);CHKERRQ(ierr);}
1069   else if (simplex)  {ierr = DMPlexCreateBoxMesh_Simplex_Internal(comm, dim, fac, low, upp, bdt, interpolate, dm);CHKERRQ(ierr);}
1070   else               {ierr = DMPlexCreateBoxMesh_Tensor_Internal(comm, dim, fac, low, upp, bdt, interpolate, dm);CHKERRQ(ierr);}
1071   PetscFunctionReturn(0);
1072 }
1073 
1074 /*@
1075   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tesselating the (x,y) plane and extruding in the third direction using wedge cells.
1076 
1077   Collective
1078 
1079   Input Parameters:
1080 + comm        - The communicator for the DM object
1081 . faces       - Number of faces per dimension, or NULL for (1, 1, 1)
1082 . lower       - The lower left corner, or NULL for (0, 0, 0)
1083 . upper       - The upper right corner, or NULL for (1, 1, 1)
1084 . periodicity - The boundary type for the X,Y,Z direction, or NULL for DM_BOUNDARY_NONE
1085 . ordExt      - If PETSC_TRUE, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1086 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1087 
1088   Output Parameter:
1089 . dm  - The DM object
1090 
1091   Level: beginner
1092 
1093 .seealso: DMPlexCreateHexCylinderMesh(), DMPlexCreateWedgeCylinderMesh(), DMPlexExtrude(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1094 @*/
1095 PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool ordExt, PetscBool interpolate, DM *dm)
1096 {
1097   DM             bdm, botdm;
1098   PetscInt       i;
1099   PetscInt       fac[3] = {0, 0, 0};
1100   PetscReal      low[3] = {0, 0, 0};
1101   PetscReal      upp[3] = {1, 1, 1};
1102   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
1103   PetscErrorCode ierr;
1104 
1105   PetscFunctionBegin;
1106   for (i = 0; i < 3; ++i) fac[i] = faces ? (faces[i] > 0 ? faces[i] : 1) : 1;
1107   if (lower) for (i = 0; i < 3; ++i) low[i] = lower[i];
1108   if (upper) for (i = 0; i < 3; ++i) upp[i] = upper[i];
1109   if (periodicity) for (i = 0; i < 3; ++i) bdt[i] = periodicity[i];
1110   for (i = 0; i < 3; ++i) if (bdt[i] != DM_BOUNDARY_NONE) SETERRQ(comm, PETSC_ERR_SUP, "Periodicity not yet supported");
1111 
1112   ierr = DMCreate(comm, &bdm);CHKERRQ(ierr);
1113   ierr = DMSetType(bdm, DMPLEX);CHKERRQ(ierr);
1114   ierr = DMSetDimension(bdm, 1);CHKERRQ(ierr);
1115   ierr = DMSetCoordinateDim(bdm, 2);CHKERRQ(ierr);
1116   ierr = DMPlexCreateSquareBoundary(bdm, low, upp, fac);CHKERRQ(ierr);
1117   ierr = DMPlexGenerate(bdm, NULL, PETSC_FALSE, &botdm);CHKERRQ(ierr);
1118   ierr = DMDestroy(&bdm);CHKERRQ(ierr);
1119   ierr = DMPlexExtrude(botdm, fac[2], upp[2] - low[2], ordExt, interpolate, dm);CHKERRQ(ierr);
1120   if (low[2] != 0.0) {
1121     Vec         v;
1122     PetscScalar *x;
1123     PetscInt    cDim, n;
1124 
1125     ierr = DMGetCoordinatesLocal(*dm, &v);CHKERRQ(ierr);
1126     ierr = VecGetBlockSize(v, &cDim);CHKERRQ(ierr);
1127     ierr = VecGetLocalSize(v, &n);CHKERRQ(ierr);
1128     ierr = VecGetArray(v, &x);CHKERRQ(ierr);
1129     x   += cDim;
1130     for (i=0; i<n; i+=cDim) x[i] += low[2];
1131     ierr = VecRestoreArray(v,&x);CHKERRQ(ierr);
1132     ierr = DMSetCoordinatesLocal(*dm, v);CHKERRQ(ierr);
1133   }
1134   ierr = DMDestroy(&botdm);CHKERRQ(ierr);
1135   PetscFunctionReturn(0);
1136 }
1137 
1138 /*@
1139   DMPlexExtrude - Creates a (d+1)-D mesh by extruding a d-D mesh in the normal direction using prismatic cells.
1140 
1141   Collective on idm
1142 
1143   Input Parameters:
1144 + idm - The mesh to be extruted
1145 . layers - The number of layers
1146 . height - The height of the extruded layer
1147 . ordExt - If PETSC_TRUE, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
1148 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
1149 
1150   Output Parameter:
1151 . dm  - The DM object
1152 
1153   Notes: The object created is an hybrid mesh, the vertex ordering in the cone of the cell is that of the prismatic cells
1154 
1155   Level: advanced
1156 
1157 .seealso: DMPlexCreateWedgeCylinderMesh(), DMPlexCreateWedgeBoxMesh(), DMPlexSetHybridBounds(), DMSetType(), DMCreate()
1158 @*/
1159 PetscErrorCode DMPlexExtrude(DM idm, PetscInt layers, PetscReal height, PetscBool ordExt, PetscBool interpolate, DM* dm)
1160 {
1161   PetscScalar       *coordsB;
1162   const PetscScalar *coordsA;
1163   PetscReal         *normals = NULL;
1164   Vec               coordinatesA, coordinatesB;
1165   PetscSection      coordSectionA, coordSectionB;
1166   PetscInt          dim, cDim, cDimB, c, l, v, coordSize, *newCone;
1167   PetscInt          cStart, cEnd, vStart, vEnd, cellV, numCells, numVertices;
1168   PetscErrorCode    ierr;
1169 
1170   PetscFunctionBegin;
1171   PetscValidHeaderSpecific(idm, DM_CLASSID, 1);
1172   PetscValidLogicalCollectiveInt(idm, layers, 2);
1173   PetscValidLogicalCollectiveReal(idm, height, 3);
1174   PetscValidLogicalCollectiveBool(idm, interpolate, 4);
1175   ierr = DMGetDimension(idm, &dim);CHKERRQ(ierr);
1176   if (dim < 1 || dim > 3) SETERRQ1(PetscObjectComm((PetscObject)idm), PETSC_ERR_SUP, "Support for dimension %D not coded", dim);
1177 
1178   ierr = DMPlexGetHeightStratum(idm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1179   ierr = DMPlexGetDepthStratum(idm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1180   numCells = (cEnd - cStart)*layers;
1181   numVertices = (vEnd - vStart)*(layers+1);
1182   ierr = DMCreate(PetscObjectComm((PetscObject)idm), dm);CHKERRQ(ierr);
1183   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1184   ierr = DMSetDimension(*dm, dim+1);CHKERRQ(ierr);
1185   ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1186   for (c = cStart, cellV = 0; c < cEnd; ++c) {
1187     PetscInt *closure = NULL;
1188     PetscInt closureSize, numCorners = 0;
1189 
1190     ierr = DMPlexGetTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1191     for (v = 0; v < closureSize*2; v += 2) if ((closure[v] >= vStart) && (closure[v] < vEnd)) numCorners++;
1192     ierr = DMPlexRestoreTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1193     for (l = 0; l < layers; ++l) {
1194       ierr = DMPlexSetConeSize(*dm, ordExt ? layers*(c - cStart) + l : l*(cEnd - cStart) + c - cStart, 2*numCorners);CHKERRQ(ierr);
1195     }
1196     cellV = PetscMax(numCorners,cellV);
1197   }
1198   ierr = DMPlexSetHybridBounds(*dm, 0, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1199   ierr = DMSetUp(*dm);CHKERRQ(ierr);
1200 
1201   ierr = DMGetCoordinateDim(idm, &cDim);CHKERRQ(ierr);
1202   if (dim != cDim) {
1203     ierr = PetscCalloc1(cDim*(vEnd - vStart), &normals);CHKERRQ(ierr);
1204   }
1205   ierr = PetscMalloc1(3*cellV,&newCone);CHKERRQ(ierr);
1206   for (c = cStart; c < cEnd; ++c) {
1207     PetscInt *closure = NULL;
1208     PetscInt closureSize, numCorners = 0, l;
1209     PetscReal normal[3] = {0, 0, 0};
1210 
1211     if (normals) {
1212       ierr = DMPlexComputeCellGeometryFVM(idm, c, NULL, NULL, normal);CHKERRQ(ierr);
1213     }
1214     ierr = DMPlexGetTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1215     for (v = 0; v < closureSize*2; v += 2) {
1216       if ((closure[v] >= vStart) && (closure[v] < vEnd)) {
1217         PetscInt d;
1218 
1219         newCone[numCorners++] = closure[v] - vStart;
1220         if (normals) { for (d = 0; d < cDim; ++d) normals[cDim*(closure[v]-vStart)+d] += normal[d]; }
1221       }
1222     }
1223     switch (numCorners) {
1224     case 4: /* do nothing */
1225     case 2: /* do nothing */
1226       break;
1227     case 3: /* from counter-clockwise to wedge ordering */
1228       l = newCone[1];
1229       newCone[1] = newCone[2];
1230       newCone[2] = l;
1231       break;
1232     default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported number of corners: %D", numCorners);
1233     }
1234     ierr = DMPlexRestoreTransitiveClosure(idm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1235     for (l = 0; l < layers; ++l) {
1236       PetscInt i;
1237 
1238       for (i = 0; i < numCorners; ++i) {
1239         newCone[  numCorners + i] = ordExt ? (layers+1)*newCone[i] + l     + numCells :     l*(vEnd - vStart) + newCone[i] + numCells;
1240         newCone[2*numCorners + i] = ordExt ? (layers+1)*newCone[i] + l + 1 + numCells : (l+1)*(vEnd - vStart) + newCone[i] + numCells;
1241       }
1242       ierr = DMPlexSetCone(*dm, ordExt ? layers*(c - cStart) + l : l*(cEnd - cStart) + c - cStart, newCone + numCorners);CHKERRQ(ierr);
1243     }
1244   }
1245   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1246   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1247   ierr = PetscFree(newCone);CHKERRQ(ierr);
1248 
1249   cDimB = cDim == dim ? cDim+1 : cDim;
1250   ierr = DMGetCoordinateSection(*dm, &coordSectionB);CHKERRQ(ierr);
1251   ierr = PetscSectionSetNumFields(coordSectionB, 1);CHKERRQ(ierr);
1252   ierr = PetscSectionSetFieldComponents(coordSectionB, 0, cDimB);CHKERRQ(ierr);
1253   ierr = PetscSectionSetChart(coordSectionB, numCells, numCells+numVertices);CHKERRQ(ierr);
1254   for (v = numCells; v < numCells+numVertices; ++v) {
1255     ierr = PetscSectionSetDof(coordSectionB, v, cDimB);CHKERRQ(ierr);
1256     ierr = PetscSectionSetFieldDof(coordSectionB, v, 0, cDimB);CHKERRQ(ierr);
1257   }
1258   ierr = PetscSectionSetUp(coordSectionB);CHKERRQ(ierr);
1259   ierr = PetscSectionGetStorageSize(coordSectionB, &coordSize);CHKERRQ(ierr);
1260   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesB);CHKERRQ(ierr);
1261   ierr = PetscObjectSetName((PetscObject) coordinatesB, "coordinates");CHKERRQ(ierr);
1262   ierr = VecSetSizes(coordinatesB, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1263   ierr = VecSetBlockSize(coordinatesB, cDimB);CHKERRQ(ierr);
1264   ierr = VecSetType(coordinatesB,VECSTANDARD);CHKERRQ(ierr);
1265 
1266   ierr = DMGetCoordinateSection(idm, &coordSectionA);CHKERRQ(ierr);
1267   ierr = DMGetCoordinatesLocal(idm, &coordinatesA);CHKERRQ(ierr);
1268   ierr = VecGetArray(coordinatesB, &coordsB);CHKERRQ(ierr);
1269   ierr = VecGetArrayRead(coordinatesA, &coordsA);CHKERRQ(ierr);
1270   for (v = vStart; v < vEnd; ++v) {
1271     const PetscScalar *cptr;
1272     PetscReal         ones2[2] = { 0., 1.}, ones3[3] = { 0., 0., 1.};
1273     PetscReal         *normal, norm, h = height/layers;
1274     PetscInt          offA, d, cDimA = cDim;
1275 
1276     normal = normals ? normals + cDimB*(v - vStart) : (cDim > 1 ? ones3 : ones2);
1277     if (normals) {
1278       for (d = 0, norm = 0.0; d < cDimB; ++d) norm += normal[d]*normal[d];
1279       for (d = 0; d < cDimB; ++d) normal[d] *= 1./PetscSqrtReal(norm);
1280     }
1281 
1282     ierr = PetscSectionGetOffset(coordSectionA, v, &offA);CHKERRQ(ierr);
1283     cptr = coordsA + offA;
1284     for (l = 0; l < layers+1; ++l) {
1285       PetscInt offB, d, newV;
1286 
1287       newV = ordExt ? (layers+1)*(v -vStart) + l + numCells : (vEnd -vStart)*l + (v -vStart) + numCells;
1288       ierr = PetscSectionGetOffset(coordSectionB, newV, &offB);CHKERRQ(ierr);
1289       for (d = 0; d < cDimA; ++d) { coordsB[offB+d]  = cptr[d]; }
1290       for (d = 0; d < cDimB; ++d) { coordsB[offB+d] += l ? normal[d]*h : 0.0; }
1291       cptr    = coordsB + offB;
1292       cDimA   = cDimB;
1293     }
1294   }
1295   ierr = VecRestoreArrayRead(coordinatesA, &coordsA);CHKERRQ(ierr);
1296   ierr = VecRestoreArray(coordinatesB, &coordsB);CHKERRQ(ierr);
1297   ierr = DMSetCoordinatesLocal(*dm, coordinatesB);CHKERRQ(ierr);
1298   ierr = VecDestroy(&coordinatesB);CHKERRQ(ierr);
1299   ierr = PetscFree(normals);CHKERRQ(ierr);
1300   if (interpolate) {
1301     DM idm;
1302 
1303     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1304     ierr = DMPlexCopyCoordinates(*dm, idm);CHKERRQ(ierr);
1305     ierr = DMDestroy(dm);CHKERRQ(ierr);
1306     *dm  = idm;
1307   }
1308   PetscFunctionReturn(0);
1309 }
1310 
1311 /*@C
1312   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all DM options in the database.
1313 
1314   Logically Collective on dm
1315 
1316   Input Parameters:
1317 + dm - the DM context
1318 - prefix - the prefix to prepend to all option names
1319 
1320   Notes:
1321   A hyphen (-) must NOT be given at the beginning of the prefix name.
1322   The first character of all runtime options is AUTOMATICALLY the hyphen.
1323 
1324   Level: advanced
1325 
1326 .seealso: SNESSetFromOptions()
1327 @*/
1328 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1329 {
1330   DM_Plex       *mesh = (DM_Plex *) dm->data;
1331   PetscErrorCode ierr;
1332 
1333   PetscFunctionBegin;
1334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1335   ierr = PetscObjectSetOptionsPrefix((PetscObject) dm, prefix);CHKERRQ(ierr);
1336   ierr = PetscObjectSetOptionsPrefix((PetscObject) mesh->partitioner, prefix);CHKERRQ(ierr);
1337   PetscFunctionReturn(0);
1338 }
1339 
1340 /*@
1341   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
1342 
1343   Collective
1344 
1345   Input Parameters:
1346 + comm      - The communicator for the DM object
1347 . numRefine - The number of regular refinements to the basic 5 cell structure
1348 - periodicZ - The boundary type for the Z direction
1349 
1350   Output Parameter:
1351 . dm  - The DM object
1352 
1353   Note: Here is the output numbering looking from the bottom of the cylinder:
1354 $       17-----14
1355 $        |     |
1356 $        |  2  |
1357 $        |     |
1358 $ 17-----8-----7-----14
1359 $  |     |     |     |
1360 $  |  3  |  0  |  1  |
1361 $  |     |     |     |
1362 $ 19-----5-----6-----13
1363 $        |     |
1364 $        |  4  |
1365 $        |     |
1366 $       19-----13
1367 $
1368 $ and up through the top
1369 $
1370 $       18-----16
1371 $        |     |
1372 $        |  2  |
1373 $        |     |
1374 $ 18----10----11-----16
1375 $  |     |     |     |
1376 $  |  3  |  0  |  1  |
1377 $  |     |     |     |
1378 $ 20-----9----12-----15
1379 $        |     |
1380 $        |  4  |
1381 $        |     |
1382 $       20-----15
1383 
1384   Level: beginner
1385 
1386 .seealso: DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1387 @*/
1388 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, PetscInt numRefine, DMBoundaryType periodicZ, DM *dm)
1389 {
1390   const PetscInt dim = 3;
1391   PetscInt       numCells, numVertices, r;
1392   PetscMPIInt    rank;
1393   PetscErrorCode ierr;
1394 
1395   PetscFunctionBegin;
1396   PetscValidPointer(dm, 4);
1397   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1398   if (numRefine < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of refinements %D cannot be negative", numRefine);
1399   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1400   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1401   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1402   /* Create topology */
1403   {
1404     PetscInt cone[8], c;
1405 
1406     numCells    = !rank ?  5 : 0;
1407     numVertices = !rank ? 16 : 0;
1408     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1409       numCells   *= 3;
1410       numVertices = !rank ? 24 : 0;
1411     }
1412     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1413     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 8);CHKERRQ(ierr);}
1414     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1415     if (!rank) {
1416       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1417         cone[0] = 15; cone[1] = 18; cone[2] = 17; cone[3] = 16;
1418         cone[4] = 31; cone[5] = 32; cone[6] = 33; cone[7] = 34;
1419         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1420         cone[0] = 16; cone[1] = 17; cone[2] = 24; cone[3] = 23;
1421         cone[4] = 32; cone[5] = 36; cone[6] = 37; cone[7] = 33; /* 22 25 26 21 */
1422         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1423         cone[0] = 18; cone[1] = 27; cone[2] = 24; cone[3] = 17;
1424         cone[4] = 34; cone[5] = 33; cone[6] = 37; cone[7] = 38;
1425         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1426         cone[0] = 29; cone[1] = 27; cone[2] = 18; cone[3] = 15;
1427         cone[4] = 35; cone[5] = 31; cone[6] = 34; cone[7] = 38;
1428         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1429         cone[0] = 29; cone[1] = 15; cone[2] = 16; cone[3] = 23;
1430         cone[4] = 35; cone[5] = 36; cone[6] = 32; cone[7] = 31;
1431         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1432 
1433         cone[0] = 31; cone[1] = 34; cone[2] = 33; cone[3] = 32;
1434         cone[4] = 19; cone[5] = 22; cone[6] = 21; cone[7] = 20;
1435         ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1436         cone[0] = 32; cone[1] = 33; cone[2] = 37; cone[3] = 36;
1437         cone[4] = 22; cone[5] = 25; cone[6] = 26; cone[7] = 21;
1438         ierr = DMPlexSetCone(*dm, 6, cone);CHKERRQ(ierr);
1439         cone[0] = 34; cone[1] = 38; cone[2] = 37; cone[3] = 33;
1440         cone[4] = 20; cone[5] = 21; cone[6] = 26; cone[7] = 28;
1441         ierr = DMPlexSetCone(*dm, 7, cone);CHKERRQ(ierr);
1442         cone[0] = 35; cone[1] = 38; cone[2] = 34; cone[3] = 31;
1443         cone[4] = 30; cone[5] = 19; cone[6] = 20; cone[7] = 28;
1444         ierr = DMPlexSetCone(*dm, 8, cone);CHKERRQ(ierr);
1445         cone[0] = 35; cone[1] = 31; cone[2] = 32; cone[3] = 36;
1446         cone[4] = 30; cone[5] = 25; cone[6] = 22; cone[7] = 19;
1447         ierr = DMPlexSetCone(*dm, 9, cone);CHKERRQ(ierr);
1448 
1449         cone[0] = 19; cone[1] = 20; cone[2] = 21; cone[3] = 22;
1450         cone[4] = 15; cone[5] = 16; cone[6] = 17; cone[7] = 18;
1451         ierr = DMPlexSetCone(*dm, 10, cone);CHKERRQ(ierr);
1452         cone[0] = 22; cone[1] = 21; cone[2] = 26; cone[3] = 25;
1453         cone[4] = 16; cone[5] = 23; cone[6] = 24; cone[7] = 17;
1454         ierr = DMPlexSetCone(*dm, 11, cone);CHKERRQ(ierr);
1455         cone[0] = 20; cone[1] = 28; cone[2] = 26; cone[3] = 21;
1456         cone[4] = 18; cone[5] = 17; cone[6] = 24; cone[7] = 27;
1457         ierr = DMPlexSetCone(*dm, 12, cone);CHKERRQ(ierr);
1458         cone[0] = 30; cone[1] = 28; cone[2] = 20; cone[3] = 19;
1459         cone[4] = 29; cone[5] = 15; cone[6] = 18; cone[7] = 27;
1460         ierr = DMPlexSetCone(*dm, 13, cone);CHKERRQ(ierr);
1461         cone[0] = 30; cone[1] = 19; cone[2] = 22; cone[3] = 25;
1462         cone[4] = 29; cone[5] = 23; cone[6] = 16; cone[7] = 15;
1463         ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1464       } else {
1465         cone[0] =  5; cone[1] =  8; cone[2] =  7; cone[3] =  6;
1466         cone[4] =  9; cone[5] = 12; cone[6] = 11; cone[7] = 10;
1467         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1468         cone[0] =  6; cone[1] =  7; cone[2] = 14; cone[3] = 13;
1469         cone[4] = 12; cone[5] = 15; cone[6] = 16; cone[7] = 11;
1470         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1471         cone[0] =  8; cone[1] = 17; cone[2] = 14; cone[3] =  7;
1472         cone[4] = 10; cone[5] = 11; cone[6] = 16; cone[7] = 18;
1473         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1474         cone[0] = 19; cone[1] = 17; cone[2] =  8; cone[3] =  5;
1475         cone[4] = 20; cone[5] =  9; cone[6] = 10; cone[7] = 18;
1476         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1477         cone[0] = 19; cone[1] =  5; cone[2] =  6; cone[3] = 13;
1478         cone[4] = 20; cone[5] = 15; cone[6] = 12; cone[7] =  9;
1479         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1480       }
1481     }
1482     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1483     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1484   }
1485   /* Interpolate */
1486   {
1487     DM idm;
1488 
1489     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1490     ierr = DMDestroy(dm);CHKERRQ(ierr);
1491     *dm  = idm;
1492   }
1493   /* Create cube geometry */
1494   {
1495     Vec             coordinates;
1496     PetscSection    coordSection;
1497     PetscScalar    *coords;
1498     PetscInt        coordSize, v;
1499     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1500     const PetscReal ds2 = dis/2.0;
1501 
1502     /* Build coordinates */
1503     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1504     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1505     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1506     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1507     for (v = numCells; v < numCells+numVertices; ++v) {
1508       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1509       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1510     }
1511     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1512     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1513     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1514     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1515     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1516     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1517     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1518     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1519     if (!rank) {
1520       coords[0*dim+0] = -ds2; coords[0*dim+1] = -ds2; coords[0*dim+2] = 0.0;
1521       coords[1*dim+0] =  ds2; coords[1*dim+1] = -ds2; coords[1*dim+2] = 0.0;
1522       coords[2*dim+0] =  ds2; coords[2*dim+1] =  ds2; coords[2*dim+2] = 0.0;
1523       coords[3*dim+0] = -ds2; coords[3*dim+1] =  ds2; coords[3*dim+2] = 0.0;
1524       coords[4*dim+0] = -ds2; coords[4*dim+1] = -ds2; coords[4*dim+2] = 1.0;
1525       coords[5*dim+0] = -ds2; coords[5*dim+1] =  ds2; coords[5*dim+2] = 1.0;
1526       coords[6*dim+0] =  ds2; coords[6*dim+1] =  ds2; coords[6*dim+2] = 1.0;
1527       coords[7*dim+0] =  ds2; coords[7*dim+1] = -ds2; coords[7*dim+2] = 1.0;
1528       coords[ 8*dim+0] =  dis; coords[ 8*dim+1] = -dis; coords[ 8*dim+2] = 0.0;
1529       coords[ 9*dim+0] =  dis; coords[ 9*dim+1] =  dis; coords[ 9*dim+2] = 0.0;
1530       coords[10*dim+0] =  dis; coords[10*dim+1] = -dis; coords[10*dim+2] = 1.0;
1531       coords[11*dim+0] =  dis; coords[11*dim+1] =  dis; coords[11*dim+2] = 1.0;
1532       coords[12*dim+0] = -dis; coords[12*dim+1] =  dis; coords[12*dim+2] = 0.0;
1533       coords[13*dim+0] = -dis; coords[13*dim+1] =  dis; coords[13*dim+2] = 1.0;
1534       coords[14*dim+0] = -dis; coords[14*dim+1] = -dis; coords[14*dim+2] = 0.0;
1535       coords[15*dim+0] = -dis; coords[15*dim+1] = -dis; coords[15*dim+2] = 1.0;
1536       if (periodicZ == DM_BOUNDARY_PERIODIC) {
1537         /* 15 31 19 */ coords[16*dim+0] = -ds2; coords[16*dim+1] = -ds2; coords[16*dim+2] = 0.5;
1538         /* 16 32 22 */ coords[17*dim+0] =  ds2; coords[17*dim+1] = -ds2; coords[17*dim+2] = 0.5;
1539         /* 17 33 21 */ coords[18*dim+0] =  ds2; coords[18*dim+1] =  ds2; coords[18*dim+2] = 0.5;
1540         /* 18 34 20 */ coords[19*dim+0] = -ds2; coords[19*dim+1] =  ds2; coords[19*dim+2] = 0.5;
1541         /* 29 35 30 */ coords[20*dim+0] = -dis; coords[20*dim+1] = -dis; coords[20*dim+2] = 0.5;
1542         /* 23 36 25 */ coords[21*dim+0] =  dis; coords[21*dim+1] = -dis; coords[21*dim+2] = 0.5;
1543         /* 24 37 26 */ coords[22*dim+0] =  dis; coords[22*dim+1] =  dis; coords[22*dim+2] = 0.5;
1544         /* 27 38 28 */ coords[23*dim+0] = -dis; coords[23*dim+1] =  dis; coords[23*dim+2] = 0.5;
1545       }
1546     }
1547     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1548     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1549     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1550   }
1551   /* Create periodicity */
1552   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1553     PetscReal      L[3];
1554     PetscReal      maxCell[3];
1555     DMBoundaryType bdType[3];
1556     PetscReal      lower[3] = {0.0, 0.0, 0.0};
1557     PetscReal      upper[3] = {1.0, 1.0, 1.5};
1558     PetscInt       i, numZCells = 3;
1559 
1560     bdType[0] = DM_BOUNDARY_NONE;
1561     bdType[1] = DM_BOUNDARY_NONE;
1562     bdType[2] = periodicZ;
1563     for (i = 0; i < dim; i++) {
1564       L[i]       = upper[i] - lower[i];
1565       maxCell[i] = 1.1 * (L[i] / numZCells);
1566     }
1567     ierr = DMSetPeriodicity(*dm, PETSC_TRUE, maxCell, L, bdType);CHKERRQ(ierr);
1568   }
1569   /* Refine topology */
1570   for (r = 0; r < numRefine; ++r) {
1571     DM rdm = NULL;
1572 
1573     ierr = DMRefine(*dm, comm, &rdm);CHKERRQ(ierr);
1574     ierr = DMDestroy(dm);CHKERRQ(ierr);
1575     *dm  = rdm;
1576   }
1577   /* Remap geometry to cylinder
1578        Interior square: Linear interpolation is correct
1579        The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1580        such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
1581 
1582          phi     = arctan(y/x)
1583          d_close = sqrt(1/8 + 1/4 sin^2(phi))
1584          d_far   = sqrt(1/2 + sin^2(phi))
1585 
1586        so we remap them using
1587 
1588          x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1589          y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
1590 
1591        If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1592   */
1593   {
1594     Vec           coordinates;
1595     PetscSection  coordSection;
1596     PetscScalar  *coords;
1597     PetscInt      vStart, vEnd, v;
1598     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1599     const PetscReal ds2 = 0.5*dis;
1600 
1601     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1602     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1603     ierr = DMGetCoordinatesLocal(*dm, &coordinates);CHKERRQ(ierr);
1604     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1605     for (v = vStart; v < vEnd; ++v) {
1606       PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
1607       PetscInt  off;
1608 
1609       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
1610       if ((PetscAbsScalar(coords[off+0]) <= ds2) && (PetscAbsScalar(coords[off+1]) <= ds2)) continue;
1611       x    = PetscRealPart(coords[off]);
1612       y    = PetscRealPart(coords[off+1]);
1613       phi  = PetscAtan2Real(y, x);
1614       sinp = PetscSinReal(phi);
1615       cosp = PetscCosReal(phi);
1616       if ((PetscAbsReal(phi) > PETSC_PI/4.0) && (PetscAbsReal(phi) < 3.0*PETSC_PI/4.0)) {
1617         dc = PetscAbsReal(ds2/sinp);
1618         df = PetscAbsReal(dis/sinp);
1619         xc = ds2*x/PetscAbsReal(y);
1620         yc = ds2*PetscSignReal(y);
1621       } else {
1622         dc = PetscAbsReal(ds2/cosp);
1623         df = PetscAbsReal(dis/cosp);
1624         xc = ds2*PetscSignReal(x);
1625         yc = ds2*y/PetscAbsReal(x);
1626       }
1627       coords[off+0] = xc + (coords[off+0] - xc)*(1.0 - dc)/(df - dc);
1628       coords[off+1] = yc + (coords[off+1] - yc)*(1.0 - dc)/(df - dc);
1629     }
1630     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1631     if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1632       ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr);
1633     }
1634   }
1635   PetscFunctionReturn(0);
1636 }
1637 
1638 /*@
1639   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
1640 
1641   Collective
1642 
1643   Input Parameters:
1644 + comm - The communicator for the DM object
1645 . n    - The number of wedges around the origin
1646 - interpolate - Create edges and faces
1647 
1648   Output Parameter:
1649 . dm  - The DM object
1650 
1651   Level: beginner
1652 
1653 .seealso: DMPlexCreateHexCylinderMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1654 @*/
1655 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
1656 {
1657   const PetscInt dim = 3;
1658   PetscInt       numCells, numVertices;
1659   PetscMPIInt    rank;
1660   PetscErrorCode ierr;
1661 
1662   PetscFunctionBegin;
1663   PetscValidPointer(dm, 3);
1664   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1665   if (n < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %D cannot be negative", n);
1666   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1667   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1668   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1669   /* Create topology */
1670   {
1671     PetscInt cone[6], c;
1672 
1673     numCells    = !rank ?        n : 0;
1674     numVertices = !rank ?  2*(n+1) : 0;
1675     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1676     ierr = DMPlexSetHybridBounds(*dm, 0, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1677     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 6);CHKERRQ(ierr);}
1678     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1679     for (c = 0; c < numCells; c++) {
1680       cone[0] =  c+n*1; cone[1] = (c+1)%n+n*1; cone[2] = 0+3*n;
1681       cone[3] =  c+n*2; cone[4] = (c+1)%n+n*2; cone[5] = 1+3*n;
1682       ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
1683     }
1684     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1685     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1686   }
1687   /* Interpolate */
1688   if (interpolate) {
1689     DM idm;
1690 
1691     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1692     ierr = DMDestroy(dm);CHKERRQ(ierr);
1693     *dm  = idm;
1694   }
1695   /* Create cylinder geometry */
1696   {
1697     Vec          coordinates;
1698     PetscSection coordSection;
1699     PetscScalar *coords;
1700     PetscInt     coordSize, v, c;
1701 
1702     /* Build coordinates */
1703     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1704     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1705     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1706     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1707     for (v = numCells; v < numCells+numVertices; ++v) {
1708       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1709       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1710     }
1711     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1712     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1713     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1714     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1715     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1716     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1717     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1718     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1719     for (c = 0; c < numCells; c++) {
1720       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;
1721       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;
1722     }
1723     if (!rank) {
1724       coords[(2*n+0)*dim+0] = 0.0; coords[(2*n+0)*dim+1] = 0.0; coords[(2*n+0)*dim+2] = 1.0;
1725       coords[(2*n+1)*dim+0] = 0.0; coords[(2*n+1)*dim+1] = 0.0; coords[(2*n+1)*dim+2] = 0.0;
1726     }
1727     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1728     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1729     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1730   }
1731   PetscFunctionReturn(0);
1732 }
1733 
1734 PETSC_STATIC_INLINE PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1735 {
1736   PetscReal prod = 0.0;
1737   PetscInt  i;
1738   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
1739   return PetscSqrtReal(prod);
1740 }
1741 PETSC_STATIC_INLINE PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1742 {
1743   PetscReal prod = 0.0;
1744   PetscInt  i;
1745   for (i = 0; i < dim; ++i) prod += x[i]*y[i];
1746   return prod;
1747 }
1748 
1749 /*@
1750   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
1751 
1752   Collective
1753 
1754   Input Parameters:
1755 + comm  - The communicator for the DM object
1756 . dim   - The dimension
1757 - simplex - Use simplices, or tensor product cells
1758 
1759   Output Parameter:
1760 . dm  - The DM object
1761 
1762   Level: beginner
1763 
1764 .seealso: DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1765 @*/
1766 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *dm)
1767 {
1768   const PetscInt  embedDim = dim+1;
1769   PetscSection    coordSection;
1770   Vec             coordinates;
1771   PetscScalar    *coords;
1772   PetscReal      *coordsIn;
1773   PetscInt        numCells, numEdges, numVerts, firstVertex, v, firstEdge, coordSize, d, c, e;
1774   PetscMPIInt     rank;
1775   PetscErrorCode  ierr;
1776 
1777   PetscFunctionBegin;
1778   PetscValidPointer(dm, 4);
1779   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1780   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1781   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1782   ierr = DMSetCoordinateDim(*dm, dim+1);CHKERRQ(ierr);
1783   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) *dm), &rank);CHKERRQ(ierr);
1784   switch (dim) {
1785   case 2:
1786     if (simplex) {
1787       DM              idm;
1788       const PetscReal edgeLen     = 2.0/(1.0 + PETSC_PHI);
1789       const PetscReal vertex[3]   = {0.0, 1.0/(1.0 + PETSC_PHI), PETSC_PHI/(1.0 + PETSC_PHI)};
1790       const PetscInt  degree      = 5;
1791       PetscInt        s[3]        = {1, 1, 1};
1792       PetscInt        cone[3];
1793       PetscInt       *graph, p, i, j, k;
1794 
1795       numCells    = !rank ? 20 : 0;
1796       numVerts    = !rank ? 12 : 0;
1797       firstVertex = numCells;
1798       /* Use icosahedron, which for a unit sphere has coordinates which are all cyclic permutations of
1799 
1800            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
1801 
1802          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
1803          length is then given by 2/\phi = 2 * 0.61803 = 1.23606.
1804       */
1805       /* Construct vertices */
1806       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1807       if (!rank) {
1808         for (p = 0, i = 0; p < embedDim; ++p) {
1809           for (s[1] = -1; s[1] < 2; s[1] += 2) {
1810             for (s[2] = -1; s[2] < 2; s[2] += 2) {
1811               for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertex[(d+p)%embedDim];
1812               ++i;
1813             }
1814           }
1815         }
1816       }
1817       /* Construct graph */
1818       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
1819       for (i = 0; i < numVerts; ++i) {
1820         for (j = 0, k = 0; j < numVerts; ++j) {
1821           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
1822         }
1823         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid icosahedron, vertex %D degree %D != %D", i, k, degree);
1824       }
1825       /* Build Topology */
1826       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
1827       for (c = 0; c < numCells; c++) {
1828         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
1829       }
1830       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1831       /* Cells */
1832       for (i = 0, c = 0; i < numVerts; ++i) {
1833         for (j = 0; j < i; ++j) {
1834           for (k = 0; k < j; ++k) {
1835             if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i]) {
1836               cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k;
1837               /* Check orientation */
1838               {
1839                 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}}};
1840                 PetscReal normal[3];
1841                 PetscInt  e, f;
1842 
1843                 for (d = 0; d < embedDim; ++d) {
1844                   normal[d] = 0.0;
1845                   for (e = 0; e < embedDim; ++e) {
1846                     for (f = 0; f < embedDim; ++f) {
1847                       normal[d] += epsilon[d][e][f]*(coordsIn[j*embedDim+e] - coordsIn[i*embedDim+e])*(coordsIn[k*embedDim+f] - coordsIn[i*embedDim+f]);
1848                     }
1849                   }
1850                 }
1851                 if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
1852               }
1853               ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
1854             }
1855           }
1856         }
1857       }
1858       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1859       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1860       ierr = PetscFree(graph);CHKERRQ(ierr);
1861       /* Interpolate mesh */
1862       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1863       ierr = DMDestroy(dm);CHKERRQ(ierr);
1864       *dm  = idm;
1865     } else {
1866       /*
1867         12-21--13
1868          |     |
1869         25  4  24
1870          |     |
1871   12-25--9-16--8-24--13
1872    |     |     |     |
1873   23  5 17  0 15  3  22
1874    |     |     |     |
1875   10-20--6-14--7-19--11
1876          |     |
1877         20  1  19
1878          |     |
1879         10-18--11
1880          |     |
1881         23  2  22
1882          |     |
1883         12-21--13
1884        */
1885       const PetscReal dist = 1.0/PetscSqrtReal(3.0);
1886       PetscInt        cone[4], ornt[4];
1887 
1888       numCells    = !rank ?  6 : 0;
1889       numEdges    = !rank ? 12 : 0;
1890       numVerts    = !rank ?  8 : 0;
1891       firstVertex = numCells;
1892       firstEdge   = numCells + numVerts;
1893       /* Build Topology */
1894       ierr = DMPlexSetChart(*dm, 0, numCells+numEdges+numVerts);CHKERRQ(ierr);
1895       for (c = 0; c < numCells; c++) {
1896         ierr = DMPlexSetConeSize(*dm, c, 4);CHKERRQ(ierr);
1897       }
1898       for (e = firstEdge; e < firstEdge+numEdges; ++e) {
1899         ierr = DMPlexSetConeSize(*dm, e, 2);CHKERRQ(ierr);
1900       }
1901       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1902       if (!rank) {
1903         /* Cell 0 */
1904         cone[0] = 14; cone[1] = 15; cone[2] = 16; cone[3] = 17;
1905         ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1906         ornt[0] = 0; ornt[1] = 0; ornt[2] = 0; ornt[3] = 0;
1907         ierr = DMPlexSetConeOrientation(*dm, 0, ornt);CHKERRQ(ierr);
1908         /* Cell 1 */
1909         cone[0] = 18; cone[1] = 19; cone[2] = 14; cone[3] = 20;
1910         ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1911         ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1912         ierr = DMPlexSetConeOrientation(*dm, 1, ornt);CHKERRQ(ierr);
1913         /* Cell 2 */
1914         cone[0] = 21; cone[1] = 22; cone[2] = 18; cone[3] = 23;
1915         ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1916         ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1917         ierr = DMPlexSetConeOrientation(*dm, 2, ornt);CHKERRQ(ierr);
1918         /* Cell 3 */
1919         cone[0] = 19; cone[1] = 22; cone[2] = 24; cone[3] = 15;
1920         ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1921         ornt[0] = -2; ornt[1] = -2; ornt[2] = 0; ornt[3] = -2;
1922         ierr = DMPlexSetConeOrientation(*dm, 3, ornt);CHKERRQ(ierr);
1923         /* Cell 4 */
1924         cone[0] = 16; cone[1] = 24; cone[2] = 21; cone[3] = 25;
1925         ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1926         ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = 0;
1927         ierr = DMPlexSetConeOrientation(*dm, 4, ornt);CHKERRQ(ierr);
1928         /* Cell 5 */
1929         cone[0] = 20; cone[1] = 17; cone[2] = 25; cone[3] = 23;
1930         ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1931         ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = -2;
1932         ierr = DMPlexSetConeOrientation(*dm, 5, ornt);CHKERRQ(ierr);
1933         /* Edges */
1934         cone[0] =  6; cone[1] =  7;
1935         ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1936         cone[0] =  7; cone[1] =  8;
1937         ierr = DMPlexSetCone(*dm, 15, cone);CHKERRQ(ierr);
1938         cone[0] =  8; cone[1] =  9;
1939         ierr = DMPlexSetCone(*dm, 16, cone);CHKERRQ(ierr);
1940         cone[0] =  9; cone[1] =  6;
1941         ierr = DMPlexSetCone(*dm, 17, cone);CHKERRQ(ierr);
1942         cone[0] = 10; cone[1] = 11;
1943         ierr = DMPlexSetCone(*dm, 18, cone);CHKERRQ(ierr);
1944         cone[0] = 11; cone[1] =  7;
1945         ierr = DMPlexSetCone(*dm, 19, cone);CHKERRQ(ierr);
1946         cone[0] =  6; cone[1] = 10;
1947         ierr = DMPlexSetCone(*dm, 20, cone);CHKERRQ(ierr);
1948         cone[0] = 12; cone[1] = 13;
1949         ierr = DMPlexSetCone(*dm, 21, cone);CHKERRQ(ierr);
1950         cone[0] = 13; cone[1] = 11;
1951         ierr = DMPlexSetCone(*dm, 22, cone);CHKERRQ(ierr);
1952         cone[0] = 10; cone[1] = 12;
1953         ierr = DMPlexSetCone(*dm, 23, cone);CHKERRQ(ierr);
1954         cone[0] = 13; cone[1] =  8;
1955         ierr = DMPlexSetCone(*dm, 24, cone);CHKERRQ(ierr);
1956         cone[0] = 12; cone[1] =  9;
1957         ierr = DMPlexSetCone(*dm, 25, cone);CHKERRQ(ierr);
1958       }
1959       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1960       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1961       /* Build coordinates */
1962       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1963       if (!rank) {
1964         coordsIn[0*embedDim+0] = -dist; coordsIn[0*embedDim+1] =  dist; coordsIn[0*embedDim+2] = -dist;
1965         coordsIn[1*embedDim+0] =  dist; coordsIn[1*embedDim+1] =  dist; coordsIn[1*embedDim+2] = -dist;
1966         coordsIn[2*embedDim+0] =  dist; coordsIn[2*embedDim+1] = -dist; coordsIn[2*embedDim+2] = -dist;
1967         coordsIn[3*embedDim+0] = -dist; coordsIn[3*embedDim+1] = -dist; coordsIn[3*embedDim+2] = -dist;
1968         coordsIn[4*embedDim+0] = -dist; coordsIn[4*embedDim+1] =  dist; coordsIn[4*embedDim+2] =  dist;
1969         coordsIn[5*embedDim+0] =  dist; coordsIn[5*embedDim+1] =  dist; coordsIn[5*embedDim+2] =  dist;
1970         coordsIn[6*embedDim+0] = -dist; coordsIn[6*embedDim+1] = -dist; coordsIn[6*embedDim+2] =  dist;
1971         coordsIn[7*embedDim+0] =  dist; coordsIn[7*embedDim+1] = -dist; coordsIn[7*embedDim+2] =  dist;
1972       }
1973     }
1974     break;
1975   case 3:
1976     if (simplex) {
1977       DM              idm;
1978       const PetscReal edgeLen         = 1.0/PETSC_PHI;
1979       const PetscReal vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
1980       const PetscReal vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
1981       const PetscReal vertexC[4]      = {0.5, 0.5*PETSC_PHI, 0.5/PETSC_PHI, 0.0};
1982       const PetscInt  degree          = 12;
1983       PetscInt        s[4]            = {1, 1, 1};
1984       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},
1985                                          {2, 0, 1, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 2, 1, 0}};
1986       PetscInt        cone[4];
1987       PetscInt       *graph, p, i, j, k, l;
1988 
1989       numCells    = !rank ? 600 : 0;
1990       numVerts    = !rank ? 120 : 0;
1991       firstVertex = numCells;
1992       /* Use the 600-cell, which for a unit sphere has coordinates which are
1993 
1994            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
1995                (\pm 1,    0,       0,      0)  all cyclic permutations   8
1996            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
1997 
1998          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
1999          length is then given by 1/\phi = 0.61803.
2000 
2001          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
2002          http://mathworld.wolfram.com/600-Cell.html
2003       */
2004       /* Construct vertices */
2005       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
2006       i    = 0;
2007       if (!rank) {
2008         for (s[0] = -1; s[0] < 2; s[0] += 2) {
2009           for (s[1] = -1; s[1] < 2; s[1] += 2) {
2010             for (s[2] = -1; s[2] < 2; s[2] += 2) {
2011               for (s[3] = -1; s[3] < 2; s[3] += 2) {
2012                 for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[d]*vertexA[d];
2013                 ++i;
2014               }
2015             }
2016           }
2017         }
2018         for (p = 0; p < embedDim; ++p) {
2019           s[1] = s[2] = s[3] = 1;
2020           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2021             for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertexB[(d+p)%embedDim];
2022             ++i;
2023           }
2024         }
2025         for (p = 0; p < 12; ++p) {
2026           s[3] = 1;
2027           for (s[0] = -1; s[0] < 2; s[0] += 2) {
2028             for (s[1] = -1; s[1] < 2; s[1] += 2) {
2029               for (s[2] = -1; s[2] < 2; s[2] += 2) {
2030                 for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[evenPerm[p][d]]*vertexC[evenPerm[p][d]];
2031                 ++i;
2032               }
2033             }
2034           }
2035         }
2036       }
2037       if (i != numVerts) SETERRQ2(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertices %D != %D", i, numVerts);
2038       /* Construct graph */
2039       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
2040       for (i = 0; i < numVerts; ++i) {
2041         for (j = 0, k = 0; j < numVerts; ++j) {
2042           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
2043         }
2044         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertex %D degree %D != %D", i, k, degree);
2045       }
2046       /* Build Topology */
2047       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
2048       for (c = 0; c < numCells; c++) {
2049         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
2050       }
2051       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
2052       /* Cells */
2053       if (!rank) {
2054         for (i = 0, c = 0; i < numVerts; ++i) {
2055           for (j = 0; j < i; ++j) {
2056             for (k = 0; k < j; ++k) {
2057               for (l = 0; l < k; ++l) {
2058                 if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i] &&
2059                     graph[l*numVerts+i] && graph[l*numVerts+j] && graph[l*numVerts+k]) {
2060                   cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k; cone[3] = firstVertex+l;
2061                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
2062                   {
2063                     const PetscInt epsilon[4][4][4][4] = {{{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2064                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  1}, { 0,  0, -1, 0}},
2065                                                            {{0,  0,  0,  0}, { 0, 0,  0, -1}, { 0,  0, 0,  0}, { 0,  1,  0, 0}},
2066                                                            {{0,  0,  0,  0}, { 0, 0,  1,  0}, { 0, -1, 0,  0}, { 0,  0,  0, 0}}},
2067 
2068                                                           {{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0, -1}, { 0,  0,  1, 0}},
2069                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2070                                                            {{0,  0,  0,  1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, {-1,  0,  0, 0}},
2071                                                            {{0,  0, -1,  0}, { 0, 0,  0,  0}, { 1,  0, 0,  0}, { 0,  0,  0, 0}}},
2072 
2073                                                           {{{0,  0,  0,  0}, { 0, 0,  0,  1}, { 0,  0, 0,  0}, { 0, -1,  0, 0}},
2074                                                            {{0,  0,  0, -1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 1,  0,  0, 0}},
2075                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2076                                                            {{0,  1,  0,  0}, {-1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}},
2077 
2078                                                           {{{0,  0,  0,  0}, { 0, 0, -1,  0}, { 0,  1, 0,  0}, { 0,  0,  0, 0}},
2079                                                            {{0,  0,  1,  0}, { 0, 0,  0,  0}, {-1,  0, 0,  0}, { 0,  0,  0, 0}},
2080                                                            {{0, -1,  0,  0}, { 1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
2081                                                            {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}}};
2082                     PetscReal normal[4];
2083                     PetscInt  e, f, g;
2084 
2085                     for (d = 0; d < embedDim; ++d) {
2086                       normal[d] = 0.0;
2087                       for (e = 0; e < embedDim; ++e) {
2088                         for (f = 0; f < embedDim; ++f) {
2089                           for (g = 0; g < embedDim; ++g) {
2090                             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]);
2091                           }
2092                         }
2093                       }
2094                     }
2095                     if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
2096                   }
2097                   ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
2098                 }
2099               }
2100             }
2101           }
2102         }
2103       }
2104       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
2105       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
2106       ierr = PetscFree(graph);CHKERRQ(ierr);
2107       /* Interpolate mesh */
2108       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2109       ierr = DMDestroy(dm);CHKERRQ(ierr);
2110       *dm  = idm;
2111       break;
2112     }
2113   default: SETERRQ1(comm, PETSC_ERR_SUP, "Unsupported dimension for sphere: %D", dim);
2114   }
2115   /* Create coordinates */
2116   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
2117   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2118   ierr = PetscSectionSetFieldComponents(coordSection, 0, embedDim);CHKERRQ(ierr);
2119   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numVerts);CHKERRQ(ierr);
2120   for (v = firstVertex; v < firstVertex+numVerts; ++v) {
2121     ierr = PetscSectionSetDof(coordSection, v, embedDim);CHKERRQ(ierr);
2122     ierr = PetscSectionSetFieldDof(coordSection, v, 0, embedDim);CHKERRQ(ierr);
2123   }
2124   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2125   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
2126   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
2127   ierr = VecSetBlockSize(coordinates, embedDim);CHKERRQ(ierr);
2128   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2129   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2130   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
2131   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2132   for (v = 0; v < numVerts; ++v) for (d = 0; d < embedDim; ++d) {coords[v*embedDim+d] = coordsIn[v*embedDim+d];}
2133   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2134   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
2135   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2136   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
2137   PetscFunctionReturn(0);
2138 }
2139 
2140 /* External function declarations here */
2141 extern PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling);
2142 extern PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat);
2143 extern PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mat);
2144 extern PetscErrorCode DMCreateLocalSection_Plex(DM dm);
2145 extern PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm);
2146 extern PetscErrorCode DMCreateMatrix_Plex(DM dm,  Mat *J);
2147 extern PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm);
2148 extern PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field);
2149 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm);
2150 extern PetscErrorCode DMSetUp_Plex(DM dm);
2151 extern PetscErrorCode DMDestroy_Plex(DM dm);
2152 extern PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer);
2153 extern PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer);
2154 extern PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm);
2155 extern PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm);
2156 static PetscErrorCode DMInitialize_Plex(DM dm);
2157 
2158 /* Replace dm with the contents of dmNew
2159    - Share the DM_Plex structure
2160    - Share the coordinates
2161    - Share the SF
2162 */
2163 static PetscErrorCode DMPlexReplace_Static(DM dm, DM dmNew)
2164 {
2165   PetscSF               sf;
2166   DM                    coordDM, coarseDM;
2167   Vec                   coords;
2168   PetscBool             isper;
2169   const PetscReal      *maxCell, *L;
2170   const DMBoundaryType *bd;
2171   PetscErrorCode        ierr;
2172 
2173   PetscFunctionBegin;
2174   ierr = DMGetPointSF(dmNew, &sf);CHKERRQ(ierr);
2175   ierr = DMSetPointSF(dm, sf);CHKERRQ(ierr);
2176   ierr = DMGetCoordinateDM(dmNew, &coordDM);CHKERRQ(ierr);
2177   ierr = DMGetCoordinatesLocal(dmNew, &coords);CHKERRQ(ierr);
2178   ierr = DMSetCoordinateDM(dm, coordDM);CHKERRQ(ierr);
2179   ierr = DMSetCoordinatesLocal(dm, coords);CHKERRQ(ierr);
2180   ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
2181   ierr = DMSetPeriodicity(dmNew, isper, maxCell, L, bd);CHKERRQ(ierr);
2182   ierr = DMDestroy_Plex(dm);CHKERRQ(ierr);
2183   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
2184   dm->data = dmNew->data;
2185   ((DM_Plex *) dmNew->data)->refct++;
2186   ierr = DMDestroyLabelLinkList_Internal(dm);CHKERRQ(ierr);
2187   ierr = DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE);CHKERRQ(ierr);
2188   ierr = DMGetCoarseDM(dmNew,&coarseDM);CHKERRQ(ierr);
2189   ierr = DMSetCoarseDM(dm,coarseDM);CHKERRQ(ierr);
2190   PetscFunctionReturn(0);
2191 }
2192 
2193 /* Swap dm with the contents of dmNew
2194    - Swap the DM_Plex structure
2195    - Swap the coordinates
2196    - Swap the point PetscSF
2197 */
2198 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
2199 {
2200   DM              coordDMA, coordDMB;
2201   Vec             coordsA,  coordsB;
2202   PetscSF         sfA,      sfB;
2203   void            *tmp;
2204   DMLabelLink     listTmp;
2205   DMLabel         depthTmp;
2206   PetscInt        tmpI;
2207   PetscErrorCode  ierr;
2208 
2209   PetscFunctionBegin;
2210   ierr = DMGetPointSF(dmA, &sfA);CHKERRQ(ierr);
2211   ierr = DMGetPointSF(dmB, &sfB);CHKERRQ(ierr);
2212   ierr = PetscObjectReference((PetscObject) sfA);CHKERRQ(ierr);
2213   ierr = DMSetPointSF(dmA, sfB);CHKERRQ(ierr);
2214   ierr = DMSetPointSF(dmB, sfA);CHKERRQ(ierr);
2215   ierr = PetscObjectDereference((PetscObject) sfA);CHKERRQ(ierr);
2216 
2217   ierr = DMGetCoordinateDM(dmA, &coordDMA);CHKERRQ(ierr);
2218   ierr = DMGetCoordinateDM(dmB, &coordDMB);CHKERRQ(ierr);
2219   ierr = PetscObjectReference((PetscObject) coordDMA);CHKERRQ(ierr);
2220   ierr = DMSetCoordinateDM(dmA, coordDMB);CHKERRQ(ierr);
2221   ierr = DMSetCoordinateDM(dmB, coordDMA);CHKERRQ(ierr);
2222   ierr = PetscObjectDereference((PetscObject) coordDMA);CHKERRQ(ierr);
2223 
2224   ierr = DMGetCoordinatesLocal(dmA, &coordsA);CHKERRQ(ierr);
2225   ierr = DMGetCoordinatesLocal(dmB, &coordsB);CHKERRQ(ierr);
2226   ierr = PetscObjectReference((PetscObject) coordsA);CHKERRQ(ierr);
2227   ierr = DMSetCoordinatesLocal(dmA, coordsB);CHKERRQ(ierr);
2228   ierr = DMSetCoordinatesLocal(dmB, coordsA);CHKERRQ(ierr);
2229   ierr = PetscObjectDereference((PetscObject) coordsA);CHKERRQ(ierr);
2230 
2231   tmp       = dmA->data;
2232   dmA->data = dmB->data;
2233   dmB->data = tmp;
2234   listTmp   = dmA->labels;
2235   dmA->labels = dmB->labels;
2236   dmB->labels = listTmp;
2237   depthTmp  = dmA->depthLabel;
2238   dmA->depthLabel = dmB->depthLabel;
2239   dmB->depthLabel = depthTmp;
2240   tmpI         = dmA->levelup;
2241   dmA->levelup = dmB->levelup;
2242   dmB->levelup = tmpI;
2243   PetscFunctionReturn(0);
2244 }
2245 
2246 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
2247 {
2248   DM_Plex       *mesh = (DM_Plex*) dm->data;
2249   PetscBool      flg;
2250   PetscErrorCode ierr;
2251 
2252   PetscFunctionBegin;
2253   /* Handle viewing */
2254   ierr = PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL);CHKERRQ(ierr);
2255   ierr = PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL,0);CHKERRQ(ierr);
2256   ierr = PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL);CHKERRQ(ierr);
2257   ierr = PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL,0);CHKERRQ(ierr);
2258   ierr = DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg);CHKERRQ(ierr);
2259   if (flg) {ierr = PetscLogDefaultBegin();CHKERRQ(ierr);}
2260   /* Point Location */
2261   ierr = PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL);CHKERRQ(ierr);
2262   /* Partitioning and distribution */
2263   ierr = PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL);CHKERRQ(ierr);
2264   /* Generation and remeshing */
2265   ierr = PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL);CHKERRQ(ierr);
2266   /* Projection behavior */
2267   ierr = PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maxmimum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL,0);CHKERRQ(ierr);
2268   ierr = PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL);CHKERRQ(ierr);
2269   /* Checking structure */
2270   {
2271     PetscBool   flg = PETSC_FALSE, flg2 = PETSC_FALSE, all = PETSC_FALSE;
2272 
2273     ierr = PetscOptionsBool("-dm_plex_check_all", "Perform all checks", NULL, PETSC_FALSE, &all, &flg2);CHKERRQ(ierr);
2274     ierr = PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2275     if (all || (flg && flg2)) {ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);}
2276     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);
2277     if (all || (flg && flg2)) {ierr = DMPlexCheckSkeleton(dm, 0);CHKERRQ(ierr);}
2278     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);
2279     if (all || (flg && flg2)) {ierr = DMPlexCheckFaces(dm, 0);CHKERRQ(ierr);}
2280     ierr = PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2281     if (all || (flg && flg2)) {ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);}
2282     ierr = PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2);CHKERRQ(ierr);
2283     if (all || (flg && flg2)) {ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);}
2284     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);
2285     if (all || (flg && flg2)) {ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);}
2286   }
2287 
2288   ierr = PetscPartitionerSetFromOptions(mesh->partitioner);CHKERRQ(ierr);
2289   PetscFunctionReturn(0);
2290 }
2291 
2292 static PetscErrorCode DMSetFromOptions_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
2293 {
2294   PetscInt       refine = 0, coarsen = 0, r;
2295   PetscBool      isHierarchy;
2296   PetscErrorCode ierr;
2297 
2298   PetscFunctionBegin;
2299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2300   ierr = PetscOptionsHead(PetscOptionsObject,"DMPlex Options");CHKERRQ(ierr);
2301   /* Handle DMPlex refinement */
2302   ierr = PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL,0);CHKERRQ(ierr);
2303   ierr = PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy,0);CHKERRQ(ierr);
2304   if (refine) {ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE);CHKERRQ(ierr);}
2305   if (refine && isHierarchy) {
2306     DM *dms, coarseDM;
2307 
2308     ierr = DMGetCoarseDM(dm, &coarseDM);CHKERRQ(ierr);
2309     ierr = PetscObjectReference((PetscObject)coarseDM);CHKERRQ(ierr);
2310     ierr = PetscMalloc1(refine,&dms);CHKERRQ(ierr);
2311     ierr = DMRefineHierarchy(dm, refine, dms);CHKERRQ(ierr);
2312     /* Total hack since we do not pass in a pointer */
2313     ierr = DMPlexSwap_Static(dm, dms[refine-1]);CHKERRQ(ierr);
2314     if (refine == 1) {
2315       ierr = DMSetCoarseDM(dm, dms[0]);CHKERRQ(ierr);
2316       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
2317     } else {
2318       ierr = DMSetCoarseDM(dm, dms[refine-2]);CHKERRQ(ierr);
2319       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
2320       ierr = DMSetCoarseDM(dms[0], dms[refine-1]);CHKERRQ(ierr);
2321       ierr = DMPlexSetRegularRefinement(dms[0], PETSC_TRUE);CHKERRQ(ierr);
2322     }
2323     ierr = DMSetCoarseDM(dms[refine-1], coarseDM);CHKERRQ(ierr);
2324     ierr = PetscObjectDereference((PetscObject)coarseDM);CHKERRQ(ierr);
2325     /* Free DMs */
2326     for (r = 0; r < refine; ++r) {
2327       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
2328       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
2329     }
2330     ierr = PetscFree(dms);CHKERRQ(ierr);
2331   } else {
2332     for (r = 0; r < refine; ++r) {
2333       DM refinedMesh;
2334 
2335       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2336       ierr = DMRefine(dm, PetscObjectComm((PetscObject) dm), &refinedMesh);CHKERRQ(ierr);
2337       /* Total hack since we do not pass in a pointer */
2338       ierr = DMPlexReplace_Static(dm, refinedMesh);CHKERRQ(ierr);
2339       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2340       ierr = DMDestroy(&refinedMesh);CHKERRQ(ierr);
2341     }
2342   }
2343   /* Handle DMPlex coarsening */
2344   ierr = PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL,0);CHKERRQ(ierr);
2345   ierr = PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy,0);CHKERRQ(ierr);
2346   if (coarsen && isHierarchy) {
2347     DM *dms;
2348 
2349     ierr = PetscMalloc1(coarsen, &dms);CHKERRQ(ierr);
2350     ierr = DMCoarsenHierarchy(dm, coarsen, dms);CHKERRQ(ierr);
2351     /* Free DMs */
2352     for (r = 0; r < coarsen; ++r) {
2353       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
2354       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
2355     }
2356     ierr = PetscFree(dms);CHKERRQ(ierr);
2357   } else {
2358     for (r = 0; r < coarsen; ++r) {
2359       DM coarseMesh;
2360 
2361       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2362       ierr = DMCoarsen(dm, PetscObjectComm((PetscObject) dm), &coarseMesh);CHKERRQ(ierr);
2363       /* Total hack since we do not pass in a pointer */
2364       ierr = DMPlexReplace_Static(dm, coarseMesh);CHKERRQ(ierr);
2365       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2366       ierr = DMDestroy(&coarseMesh);CHKERRQ(ierr);
2367     }
2368   }
2369   /* Handle */
2370   ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2371   ierr = PetscOptionsTail();CHKERRQ(ierr);
2372   PetscFunctionReturn(0);
2373 }
2374 
2375 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm,Vec *vec)
2376 {
2377   PetscErrorCode ierr;
2378 
2379   PetscFunctionBegin;
2380   ierr = DMCreateGlobalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2381   /* ierr = VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM);CHKERRQ(ierr); */
2382   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex);CHKERRQ(ierr);
2383   ierr = VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void)) VecView_Plex_Native);CHKERRQ(ierr);
2384   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex);CHKERRQ(ierr);
2385   ierr = VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void)) VecLoad_Plex_Native);CHKERRQ(ierr);
2386   PetscFunctionReturn(0);
2387 }
2388 
2389 static PetscErrorCode DMCreateLocalVector_Plex(DM dm,Vec *vec)
2390 {
2391   PetscErrorCode ierr;
2392 
2393   PetscFunctionBegin;
2394   ierr = DMCreateLocalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2395   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex_Local);CHKERRQ(ierr);
2396   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex_Local);CHKERRQ(ierr);
2397   PetscFunctionReturn(0);
2398 }
2399 
2400 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
2401 {
2402   PetscInt       depth, d;
2403   PetscErrorCode ierr;
2404 
2405   PetscFunctionBegin;
2406   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2407   if (depth == 1) {
2408     ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
2409     if (dim == 0)      {ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);}
2410     else if (dim == d) {ierr = DMPlexGetDepthStratum(dm, 1, pStart, pEnd);CHKERRQ(ierr);}
2411     else               {*pStart = 0; *pEnd = 0;}
2412   } else {
2413     ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);
2414   }
2415   PetscFunctionReturn(0);
2416 }
2417 
2418 static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
2419 {
2420   PetscSF        sf;
2421   PetscErrorCode ierr;
2422 
2423   PetscFunctionBegin;
2424   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2425   ierr = PetscSFGetRootRanks(sf, nranks, ranks, NULL, NULL, NULL);CHKERRQ(ierr);
2426   PetscFunctionReturn(0);
2427 }
2428 
2429 static PetscErrorCode DMInitialize_Plex(DM dm)
2430 {
2431   PetscErrorCode ierr;
2432 
2433   PetscFunctionBegin;
2434   dm->ops->view                            = DMView_Plex;
2435   dm->ops->load                            = DMLoad_Plex;
2436   dm->ops->setfromoptions                  = DMSetFromOptions_Plex;
2437   dm->ops->clone                           = DMClone_Plex;
2438   dm->ops->setup                           = DMSetUp_Plex;
2439   dm->ops->createlocalsection              = DMCreateLocalSection_Plex;
2440   dm->ops->createdefaultconstraints        = DMCreateDefaultConstraints_Plex;
2441   dm->ops->createglobalvector              = DMCreateGlobalVector_Plex;
2442   dm->ops->createlocalvector               = DMCreateLocalVector_Plex;
2443   dm->ops->getlocaltoglobalmapping         = NULL;
2444   dm->ops->createfieldis                   = NULL;
2445   dm->ops->createcoordinatedm              = DMCreateCoordinateDM_Plex;
2446   dm->ops->createcoordinatefield           = DMCreateCoordinateField_Plex;
2447   dm->ops->getcoloring                     = NULL;
2448   dm->ops->creatematrix                    = DMCreateMatrix_Plex;
2449   dm->ops->createinterpolation             = DMCreateInterpolation_Plex;
2450   dm->ops->createmassmatrix                = DMCreateMassMatrix_Plex;
2451   dm->ops->createinjection                 = DMCreateInjection_Plex;
2452   dm->ops->refine                          = DMRefine_Plex;
2453   dm->ops->coarsen                         = DMCoarsen_Plex;
2454   dm->ops->refinehierarchy                 = DMRefineHierarchy_Plex;
2455   dm->ops->coarsenhierarchy                = DMCoarsenHierarchy_Plex;
2456   dm->ops->adaptlabel                      = DMAdaptLabel_Plex;
2457   dm->ops->adaptmetric                     = DMAdaptMetric_Plex;
2458   dm->ops->globaltolocalbegin              = NULL;
2459   dm->ops->globaltolocalend                = NULL;
2460   dm->ops->localtoglobalbegin              = NULL;
2461   dm->ops->localtoglobalend                = NULL;
2462   dm->ops->destroy                         = DMDestroy_Plex;
2463   dm->ops->createsubdm                     = DMCreateSubDM_Plex;
2464   dm->ops->createsuperdm                   = DMCreateSuperDM_Plex;
2465   dm->ops->getdimpoints                    = DMGetDimPoints_Plex;
2466   dm->ops->locatepoints                    = DMLocatePoints_Plex;
2467   dm->ops->projectfunctionlocal            = DMProjectFunctionLocal_Plex;
2468   dm->ops->projectfunctionlabellocal       = DMProjectFunctionLabelLocal_Plex;
2469   dm->ops->projectfieldlocal               = DMProjectFieldLocal_Plex;
2470   dm->ops->projectfieldlabellocal          = DMProjectFieldLabelLocal_Plex;
2471   dm->ops->computel2diff                   = DMComputeL2Diff_Plex;
2472   dm->ops->computel2gradientdiff           = DMComputeL2GradientDiff_Plex;
2473   dm->ops->computel2fielddiff              = DMComputeL2FieldDiff_Plex;
2474   dm->ops->getneighbors                    = DMGetNeighbors_Plex;
2475   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C",DMPlexInsertBoundaryValues_Plex);CHKERRQ(ierr);
2476   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",DMSetUpGLVisViewer_Plex);CHKERRQ(ierr);
2477   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_Plex);CHKERRQ(ierr);
2478   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMPlexGetOverlap_Plex);CHKERRQ(ierr);
2479   PetscFunctionReturn(0);
2480 }
2481 
2482 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
2483 {
2484   DM_Plex        *mesh = (DM_Plex *) dm->data;
2485   PetscErrorCode ierr;
2486 
2487   PetscFunctionBegin;
2488   mesh->refct++;
2489   (*newdm)->data = mesh;
2490   ierr = PetscObjectChangeTypeName((PetscObject) *newdm, DMPLEX);CHKERRQ(ierr);
2491   ierr = DMInitialize_Plex(*newdm);CHKERRQ(ierr);
2492   PetscFunctionReturn(0);
2493 }
2494 
2495 /*MC
2496   DMPLEX = "plex" - A DM object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
2497                     In the local representation, Vecs contain all unknowns in the interior and shared boundary. This is
2498                     specified by a PetscSection object. Ownership in the global representation is determined by
2499                     ownership of the underlying DMPlex points. This is specified by another PetscSection object.
2500 
2501   Options Database Keys:
2502 + -dm_plex_hash_location             - Use grid hashing for point location
2503 . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
2504 . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
2505 . -dm_plex_max_projection_height     - Maxmimum mesh point height used to project locally
2506 . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
2507 . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
2508 . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
2509 . -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
2510 . -dm_plex_check_geometry            - Check that cells have positive volume
2511 . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
2512 . -dm_plex_view_scale <num>          - Scale the TikZ
2513 - -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
2514 
2515 
2516   Level: intermediate
2517 
2518 .seealso: DMType, DMPlexCreate(), DMCreate(), DMSetType()
2519 M*/
2520 
2521 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
2522 {
2523   DM_Plex        *mesh;
2524   PetscInt       unit, d;
2525   PetscErrorCode ierr;
2526 
2527   PetscFunctionBegin;
2528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2529   ierr     = PetscNewLog(dm,&mesh);CHKERRQ(ierr);
2530   dm->dim  = 0;
2531   dm->data = mesh;
2532 
2533   mesh->refct             = 1;
2534   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection);CHKERRQ(ierr);
2535   mesh->maxConeSize       = 0;
2536   mesh->cones             = NULL;
2537   mesh->coneOrientations  = NULL;
2538   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection);CHKERRQ(ierr);
2539   mesh->maxSupportSize    = 0;
2540   mesh->supports          = NULL;
2541   mesh->refinementUniform = PETSC_TRUE;
2542   mesh->refinementLimit   = -1.0;
2543   mesh->ghostCellStart    = -1;
2544   mesh->interpolated      = DMPLEX_INTERPOLATED_INVALID;
2545   mesh->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID;
2546 
2547   mesh->facesTmp = NULL;
2548 
2549   mesh->tetgenOpts   = NULL;
2550   mesh->triangleOpts = NULL;
2551   ierr = PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner);CHKERRQ(ierr);
2552   mesh->remeshBd     = PETSC_FALSE;
2553 
2554   mesh->subpointMap = NULL;
2555 
2556   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
2557 
2558   mesh->regularRefinement   = PETSC_FALSE;
2559   mesh->depthState          = -1;
2560   mesh->globalVertexNumbers = NULL;
2561   mesh->globalCellNumbers   = NULL;
2562   mesh->anchorSection       = NULL;
2563   mesh->anchorIS            = NULL;
2564   mesh->createanchors       = NULL;
2565   mesh->computeanchormatrix = NULL;
2566   mesh->parentSection       = NULL;
2567   mesh->parents             = NULL;
2568   mesh->childIDs            = NULL;
2569   mesh->childSection        = NULL;
2570   mesh->children            = NULL;
2571   mesh->referenceTree       = NULL;
2572   mesh->getchildsymmetry    = NULL;
2573   for (d = 0; d < 8; ++d) mesh->hybridPointMax[d] = PETSC_DETERMINE;
2574   mesh->vtkCellHeight       = 0;
2575   mesh->useAnchors          = PETSC_FALSE;
2576 
2577   mesh->maxProjectionHeight = 0;
2578 
2579   mesh->printSetValues = PETSC_FALSE;
2580   mesh->printFEM       = 0;
2581   mesh->printTol       = 1.0e-10;
2582 
2583   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
2584   PetscFunctionReturn(0);
2585 }
2586 
2587 /*@
2588   DMPlexCreate - Creates a DMPlex object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
2589 
2590   Collective
2591 
2592   Input Parameter:
2593 . comm - The communicator for the DMPlex object
2594 
2595   Output Parameter:
2596 . mesh  - The DMPlex object
2597 
2598   Level: beginner
2599 
2600 @*/
2601 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
2602 {
2603   PetscErrorCode ierr;
2604 
2605   PetscFunctionBegin;
2606   PetscValidPointer(mesh,2);
2607   ierr = DMCreate(comm, mesh);CHKERRQ(ierr);
2608   ierr = DMSetType(*mesh, DMPLEX);CHKERRQ(ierr);
2609   PetscFunctionReturn(0);
2610 }
2611 
2612 /*
2613   This takes as input the common mesh generator output, a list of the vertices for each cell, but vertex numbers are global and an SF is built for them
2614 */
2615 /* TODO: invertCells and spaceDim arguments could be added also to to DMPlexCreateFromCellListParallel(), DMPlexBuildFromCellList_Internal() and DMPlexCreateFromCellList() */
2616 PetscErrorCode DMPlexBuildFromCellList_Parallel_Internal(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[], PetscBool invertCells, PetscSF *sfVert)
2617 {
2618   PetscSF         sfPoint;
2619   PetscLayout     vLayout;
2620   PetscHSetI      vhash;
2621   PetscSFNode    *remoteVerticesAdj, *vertexLocal, *vertexOwner, *remoteVertex;
2622   const PetscInt *vrange;
2623   PetscInt        numVerticesAdj, off = 0, *verticesAdj, numVerticesGhost = 0, *localVertex, *cone, c, p, v, g;
2624   PetscMPIInt     rank, size;
2625   PetscErrorCode  ierr;
2626 
2627   PetscFunctionBegin;
2628   if (!DM_Plex_CreateFromCellList) {ierr = PetscLogEventRegister("DMPlexCrFrCeLi",DM_CLASSID,&DM_Plex_CreateFromCellList);}
2629   ierr = PetscLogEventBegin(DM_Plex_CreateFromCellList,dm,0,0,0);CHKERRQ(ierr);
2630   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2631   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2632   /* Partition vertices */
2633   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) dm), &vLayout);CHKERRQ(ierr);
2634   ierr = PetscLayoutSetLocalSize(vLayout, numVertices);CHKERRQ(ierr);
2635   ierr = PetscLayoutSetBlockSize(vLayout, 1);CHKERRQ(ierr);
2636   ierr = PetscLayoutSetUp(vLayout);CHKERRQ(ierr);
2637   ierr = PetscLayoutGetRanges(vLayout, &vrange);CHKERRQ(ierr);
2638   /* Count vertices and map them to procs */
2639   ierr = PetscHSetICreate(&vhash);CHKERRQ(ierr);
2640   for (c = 0; c < numCells; ++c) {
2641     for (p = 0; p < numCorners; ++p) {
2642       ierr = PetscHSetIAdd(vhash, cells[c*numCorners+p]);CHKERRQ(ierr);
2643     }
2644   }
2645   ierr = PetscHSetIGetSize(vhash, &numVerticesAdj);CHKERRQ(ierr);
2646   ierr = PetscMalloc1(numVerticesAdj, &verticesAdj);CHKERRQ(ierr);
2647   ierr = PetscHSetIGetElems(vhash, &off, verticesAdj);CHKERRQ(ierr);
2648   ierr = PetscHSetIDestroy(&vhash);CHKERRQ(ierr);
2649   if (off != numVerticesAdj) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %D should be %D", off, numVerticesAdj);
2650   ierr = PetscSortInt(numVerticesAdj, verticesAdj);CHKERRQ(ierr);
2651   ierr = PetscMalloc1(numVerticesAdj, &remoteVerticesAdj);CHKERRQ(ierr);
2652   for (v = 0; v < numVerticesAdj; ++v) {
2653     const PetscInt gv = verticesAdj[v];
2654     PetscInt       vrank;
2655 
2656     ierr = PetscFindInt(gv, size+1, vrange, &vrank);CHKERRQ(ierr);
2657     vrank = vrank < 0 ? -(vrank+2) : vrank;
2658     remoteVerticesAdj[v].index = gv - vrange[vrank];
2659     remoteVerticesAdj[v].rank  = vrank;
2660   }
2661   /* Create cones */
2662   ierr = DMPlexSetChart(dm, 0, numCells+numVerticesAdj);CHKERRQ(ierr);
2663   for (c = 0; c < numCells; ++c) {ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);}
2664   ierr = DMSetUp(dm);CHKERRQ(ierr);
2665   ierr = DMGetWorkArray(dm, numCorners, MPIU_INT, &cone);CHKERRQ(ierr);
2666   for (c = 0; c < numCells; ++c) {
2667     for (p = 0; p < numCorners; ++p) {
2668       const PetscInt gv = cells[c*numCorners+p];
2669       PetscInt       lv;
2670 
2671       ierr = PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv);CHKERRQ(ierr);
2672       if (lv < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %D in local connectivity", gv);
2673       cone[p] = lv+numCells;
2674     }
2675     if (invertCells) { ierr = DMPlexInvertCell_Internal(spaceDim, numCorners, cone);CHKERRQ(ierr); }
2676     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
2677   }
2678   ierr = DMRestoreWorkArray(dm, numCorners, MPIU_INT, &cone);CHKERRQ(ierr);
2679   /* Create SF for vertices */
2680   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfVert);CHKERRQ(ierr);
2681   ierr = PetscObjectSetName((PetscObject) *sfVert, "Vertex Ownership SF");CHKERRQ(ierr);
2682   ierr = PetscSFSetFromOptions(*sfVert);CHKERRQ(ierr);
2683   ierr = PetscSFSetGraph(*sfVert, numVertices, numVerticesAdj, NULL, PETSC_OWN_POINTER, remoteVerticesAdj, PETSC_OWN_POINTER);CHKERRQ(ierr);
2684   ierr = PetscFree(verticesAdj);CHKERRQ(ierr);
2685   /* Build pointSF */
2686   ierr = PetscMalloc2(numVerticesAdj, &vertexLocal, numVertices, &vertexOwner);CHKERRQ(ierr);
2687   for (v = 0; v < numVerticesAdj; ++v) {vertexLocal[v].index = v+numCells; vertexLocal[v].rank = rank;}
2688   for (v = 0; v < numVertices;    ++v) {vertexOwner[v].index = -1;         vertexOwner[v].rank = -1;}
2689   ierr = PetscSFReduceBegin(*sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2690   ierr = PetscSFReduceEnd(*sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2691   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);
2692   ierr = PetscSFBcastBegin(*sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2693   ierr = PetscSFBcastEnd(*sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2694   for (v = 0; v < numVerticesAdj; ++v) if (vertexLocal[v].rank != rank) ++numVerticesGhost;
2695   ierr = PetscMalloc1(numVerticesGhost, &localVertex);CHKERRQ(ierr);
2696   ierr = PetscMalloc1(numVerticesGhost, &remoteVertex);CHKERRQ(ierr);
2697   for (v = 0, g = 0; v < numVerticesAdj; ++v) {
2698     if (vertexLocal[v].rank != rank) {
2699       localVertex[g]        = v+numCells;
2700       remoteVertex[g].index = vertexLocal[v].index;
2701       remoteVertex[g].rank  = vertexLocal[v].rank;
2702       ++g;
2703     }
2704   }
2705   ierr = PetscFree2(vertexLocal, vertexOwner);CHKERRQ(ierr);
2706   if (g != numVerticesGhost) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of vertex ghosts %D should be %D", g, numVerticesGhost);
2707   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
2708   ierr = PetscObjectSetName((PetscObject) sfPoint, "point SF");CHKERRQ(ierr);
2709   ierr = PetscSFSetGraph(sfPoint, numCells+numVerticesAdj, numVerticesGhost, localVertex, PETSC_OWN_POINTER, remoteVertex, PETSC_OWN_POINTER);CHKERRQ(ierr);
2710   ierr = PetscLayoutDestroy(&vLayout);CHKERRQ(ierr);
2711   /* Fill in the rest of the topology structure */
2712   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2713   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2714   ierr = PetscLogEventEnd(DM_Plex_CreateFromCellList,dm,0,0,0);CHKERRQ(ierr);
2715   PetscFunctionReturn(0);
2716 }
2717 
2718 /*
2719   This takes as input the coordinates for each owned vertex
2720 */
2721 PetscErrorCode DMPlexBuildCoordinates_Parallel_Internal(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numV, PetscSF sfVert, const PetscReal vertexCoords[])
2722 {
2723   PetscSection   coordSection;
2724   Vec            coordinates;
2725   PetscScalar   *coords;
2726   PetscInt       numVertices, numVerticesAdj, coordSize, v;
2727   PetscErrorCode ierr;
2728 
2729   PetscFunctionBegin;
2730   if (!DM_Plex_CreateFromCellList_Coordinates) {ierr = PetscLogEventRegister("DMPlexCrFrCeLiCo",DM_CLASSID,&DM_Plex_CreateFromCellList_Coordinates);}
2731   ierr = PetscLogEventBegin(DM_Plex_CreateFromCellList_Coordinates,dm,0,0,0);CHKERRQ(ierr);
2732   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
2733   ierr = PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL);CHKERRQ(ierr);
2734   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2735   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2736   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
2737   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVerticesAdj);CHKERRQ(ierr);
2738   for (v = numCells; v < numCells+numVerticesAdj; ++v) {
2739     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
2740     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
2741   }
2742   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2743   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
2744   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
2745   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
2746   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2747   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2748   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
2749   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2750   {
2751     MPI_Datatype coordtype;
2752 
2753     /* Need a temp buffer for coords if we have complex/single */
2754     ierr = MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype);CHKERRQ(ierr);
2755     ierr = MPI_Type_commit(&coordtype);CHKERRQ(ierr);
2756 #if defined(PETSC_USE_COMPLEX)
2757     {
2758     PetscScalar *svertexCoords;
2759     PetscInt    i;
2760     ierr = PetscMalloc1(numV*spaceDim,&svertexCoords);CHKERRQ(ierr);
2761     for (i=0; i<numV*spaceDim; i++) svertexCoords[i] = vertexCoords[i];
2762     ierr = PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
2763     ierr = PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
2764     ierr = PetscFree(svertexCoords);CHKERRQ(ierr);
2765     }
2766 #else
2767     ierr = PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
2768     ierr = PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
2769 #endif
2770     ierr = MPI_Type_free(&coordtype);CHKERRQ(ierr);
2771   }
2772   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2773   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
2774   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2775   ierr = PetscLogEventEnd(DM_Plex_CreateFromCellList_Coordinates,dm,0,0,0);CHKERRQ(ierr);
2776   PetscFunctionReturn(0);
2777 }
2778 
2779 /*@
2780   DMPlexCreateFromCellListParallel - This takes as input common mesh generator output, a list of the vertices for each cell, and produces a DM
2781 
2782   Input Parameters:
2783 + comm - The communicator
2784 . dim - The topological dimension of the mesh
2785 . numCells - The number of cells owned by this process
2786 . numVertices - The number of vertices owned by this process
2787 . numCorners - The number of vertices for each cell
2788 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
2789 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
2790 . spaceDim - The spatial dimension used for coordinates
2791 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
2792 
2793   Output Parameter:
2794 + dm - The DM
2795 - vertexSF - Optional, SF describing complete vertex ownership
2796 
2797   Note: Two triangles sharing a face
2798 $
2799 $        2
2800 $      / | \
2801 $     /  |  \
2802 $    /   |   \
2803 $   0  0 | 1  3
2804 $    \   |   /
2805 $     \  |  /
2806 $      \ | /
2807 $        1
2808 would have input
2809 $  numCells = 2, numVertices = 4
2810 $  cells = [0 1 2  1 3 2]
2811 $
2812 which would result in the DMPlex
2813 $
2814 $        4
2815 $      / | \
2816 $     /  |  \
2817 $    /   |   \
2818 $   2  0 | 1  5
2819 $    \   |   /
2820 $     \  |  /
2821 $      \ | /
2822 $        3
2823 
2824   Level: beginner
2825 
2826 .seealso: DMPlexCreateFromCellList(), DMPlexCreateFromDAG(), DMPlexCreate()
2827 @*/
2828 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)
2829 {
2830   PetscSF        sfVert;
2831   PetscErrorCode ierr;
2832 
2833   PetscFunctionBegin;
2834   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
2835   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
2836   PetscValidLogicalCollectiveInt(*dm, dim, 2);
2837   PetscValidLogicalCollectiveInt(*dm, spaceDim, 8);
2838   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
2839   ierr = DMPlexBuildFromCellList_Parallel_Internal(*dm, spaceDim, numCells, numVertices, numCorners, cells, PETSC_FALSE, &sfVert);CHKERRQ(ierr);
2840   if (interpolate) {
2841     DM idm;
2842 
2843     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2844     ierr = DMDestroy(dm);CHKERRQ(ierr);
2845     *dm  = idm;
2846   }
2847   ierr = DMPlexBuildCoordinates_Parallel_Internal(*dm, spaceDim, numCells, numVertices, sfVert, vertexCoords);CHKERRQ(ierr);
2848   if (vertexSF) *vertexSF = sfVert;
2849   else {ierr = PetscSFDestroy(&sfVert);CHKERRQ(ierr);}
2850   PetscFunctionReturn(0);
2851 }
2852 
2853 /*
2854   This takes as input the common mesh generator output, a list of the vertices for each cell
2855 */
2856 PetscErrorCode DMPlexBuildFromCellList_Internal(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[], PetscBool invertCells)
2857 {
2858   PetscInt      *cone, c, p;
2859   PetscErrorCode ierr;
2860 
2861   PetscFunctionBegin;
2862   if (!DM_Plex_CreateFromCellList) {ierr = PetscLogEventRegister("DMPlexCrFrCeLi",DM_CLASSID,&DM_Plex_CreateFromCellList);}
2863   ierr = PetscLogEventBegin(DM_Plex_CreateFromCellList,dm,0,0,0);CHKERRQ(ierr);
2864   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
2865   for (c = 0; c < numCells; ++c) {
2866     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
2867   }
2868   ierr = DMSetUp(dm);CHKERRQ(ierr);
2869   ierr = DMGetWorkArray(dm, numCorners, MPIU_INT, &cone);CHKERRQ(ierr);
2870   for (c = 0; c < numCells; ++c) {
2871     for (p = 0; p < numCorners; ++p) {
2872       cone[p] = cells[c*numCorners+p]+numCells;
2873     }
2874     if (invertCells) { ierr = DMPlexInvertCell_Internal(spaceDim, numCorners, cone);CHKERRQ(ierr); }
2875     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
2876   }
2877   ierr = DMRestoreWorkArray(dm, numCorners, MPIU_INT, &cone);CHKERRQ(ierr);
2878   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2879   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2880   ierr = PetscLogEventEnd(DM_Plex_CreateFromCellList,dm,0,0,0);CHKERRQ(ierr);
2881   PetscFunctionReturn(0);
2882 }
2883 
2884 /*
2885   This takes as input the coordinates for each vertex
2886 */
2887 PetscErrorCode DMPlexBuildCoordinates_Internal(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
2888 {
2889   PetscSection   coordSection;
2890   Vec            coordinates;
2891   DM             cdm;
2892   PetscScalar   *coords;
2893   PetscInt       v, d;
2894   PetscErrorCode ierr;
2895 
2896   PetscFunctionBegin;
2897   if (!DM_Plex_CreateFromCellList) {ierr = PetscLogEventRegister("DMPlexCrFrCeLiCo",DM_CLASSID,&DM_Plex_CreateFromCellList_Coordinates);}
2898   ierr = PetscLogEventBegin(DM_Plex_CreateFromCellList_Coordinates,dm,0,0,0);CHKERRQ(ierr);
2899   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
2900   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2901   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2902   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
2903   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
2904   for (v = numCells; v < numCells+numVertices; ++v) {
2905     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
2906     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
2907   }
2908   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2909 
2910   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
2911   ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
2912   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
2913   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2914   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2915   for (v = 0; v < numVertices; ++v) {
2916     for (d = 0; d < spaceDim; ++d) {
2917       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
2918     }
2919   }
2920   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2921   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
2922   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2923   ierr = PetscLogEventEnd(DM_Plex_CreateFromCellList_Coordinates,dm,0,0,0);CHKERRQ(ierr);
2924   PetscFunctionReturn(0);
2925 }
2926 
2927 /*@
2928   DMPlexCreateFromCellList - This takes as input common mesh generator output, a list of the vertices for each cell, and produces a DM
2929 
2930   Input Parameters:
2931 + comm - The communicator
2932 . dim - The topological dimension of the mesh
2933 . numCells - The number of cells
2934 . numVertices - The number of vertices
2935 . numCorners - The number of vertices for each cell
2936 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
2937 . cells - An array of numCells*numCorners numbers, the vertices for each cell
2938 . spaceDim - The spatial dimension used for coordinates
2939 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
2940 
2941   Output Parameter:
2942 . dm - The DM
2943 
2944   Note: Two triangles sharing a face
2945 $
2946 $        2
2947 $      / | \
2948 $     /  |  \
2949 $    /   |   \
2950 $   0  0 | 1  3
2951 $    \   |   /
2952 $     \  |  /
2953 $      \ | /
2954 $        1
2955 would have input
2956 $  numCells = 2, numVertices = 4
2957 $  cells = [0 1 2  1 3 2]
2958 $
2959 which would result in the DMPlex
2960 $
2961 $        4
2962 $      / | \
2963 $     /  |  \
2964 $    /   |   \
2965 $   2  0 | 1  5
2966 $    \   |   /
2967 $     \  |  /
2968 $      \ | /
2969 $        3
2970 
2971   Level: beginner
2972 
2973 .seealso: DMPlexCreateFromDAG(), DMPlexCreate()
2974 @*/
2975 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)
2976 {
2977   PetscErrorCode ierr;
2978 
2979   PetscFunctionBegin;
2980   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
2981   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
2982   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
2983   ierr = DMPlexBuildFromCellList_Internal(*dm, spaceDim, numCells, numVertices, numCorners, cells, PETSC_FALSE);CHKERRQ(ierr);
2984   if (interpolate) {
2985     DM idm;
2986 
2987     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2988     ierr = DMDestroy(dm);CHKERRQ(ierr);
2989     *dm  = idm;
2990   }
2991   ierr = DMPlexBuildCoordinates_Internal(*dm, spaceDim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
2992   PetscFunctionReturn(0);
2993 }
2994 
2995 /*@
2996   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a DM
2997 
2998   Input Parameters:
2999 + dm - The empty DM object, usually from DMCreate() and DMSetDimension()
3000 . depth - The depth of the DAG
3001 . numPoints - Array of size depth + 1 containing the number of points at each depth
3002 . coneSize - The cone size of each point
3003 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
3004 . coneOrientations - The orientation of each cone point
3005 - vertexCoords - An array of numPoints[0]*spacedim numbers representing the coordinates of each vertex, with spacedim the value set via DMSetCoordinateDim()
3006 
3007   Output Parameter:
3008 . dm - The DM
3009 
3010   Note: Two triangles sharing a face would have input
3011 $  depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
3012 $  cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
3013 $ vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
3014 $
3015 which would result in the DMPlex
3016 $
3017 $        4
3018 $      / | \
3019 $     /  |  \
3020 $    /   |   \
3021 $   2  0 | 1  5
3022 $    \   |   /
3023 $     \  |  /
3024 $      \ | /
3025 $        3
3026 $
3027 $ Notice that all points are numbered consecutively, unlikely DMPlexCreateFromCellList()
3028 
3029   Level: advanced
3030 
3031 .seealso: DMPlexCreateFromCellList(), DMPlexCreate()
3032 @*/
3033 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
3034 {
3035   Vec            coordinates;
3036   PetscSection   coordSection;
3037   PetscScalar    *coords;
3038   PetscInt       coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
3039   PetscErrorCode ierr;
3040 
3041   PetscFunctionBegin;
3042   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3043   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
3044   if (dimEmbed < dim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Embedding dimension %d cannot be less than intrinsic dimension %d",dimEmbed,dim);
3045   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
3046   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
3047   for (p = pStart; p < pEnd; ++p) {
3048     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
3049     if (firstVertex < 0 && !coneSize[p - pStart]) {
3050       firstVertex = p - pStart;
3051     }
3052   }
3053   if (firstVertex < 0 && numPoints[0]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected %d vertices but could not find any", numPoints[0]);
3054   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
3055   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
3056     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
3057     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
3058   }
3059   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
3060   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
3061   /* Build coordinates */
3062   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3063   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3064   ierr = PetscSectionSetFieldComponents(coordSection, 0, dimEmbed);CHKERRQ(ierr);
3065   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
3066   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
3067     ierr = PetscSectionSetDof(coordSection, v, dimEmbed);CHKERRQ(ierr);
3068     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed);CHKERRQ(ierr);
3069   }
3070   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3071   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
3072   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
3073   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3074   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3075   ierr = VecSetBlockSize(coordinates, dimEmbed);CHKERRQ(ierr);
3076   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
3077   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3078   for (v = 0; v < numPoints[0]; ++v) {
3079     PetscInt off;
3080 
3081     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
3082     for (d = 0; d < dimEmbed; ++d) {
3083       coords[off+d] = vertexCoords[v*dimEmbed+d];
3084     }
3085   }
3086   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3087   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
3088   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3089   PetscFunctionReturn(0);
3090 }
3091 
3092 /*@C
3093   DMPlexCreateCellVertexFromFile - Create a DMPlex mesh from a simple cell-vertex file.
3094 
3095 + comm        - The MPI communicator
3096 . filename    - Name of the .dat file
3097 - interpolate - Create faces and edges in the mesh
3098 
3099   Output Parameter:
3100 . dm  - The DM object representing the mesh
3101 
3102   Note: The format is the simplest possible:
3103 $ Ne
3104 $ v0 v1 ... vk
3105 $ Nv
3106 $ x y z marker
3107 
3108   Level: beginner
3109 
3110 .seealso: DMPlexCreateFromFile(), DMPlexCreateMedFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
3111 @*/
3112 PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
3113 {
3114   DMLabel         marker;
3115   PetscViewer     viewer;
3116   Vec             coordinates;
3117   PetscSection    coordSection;
3118   PetscScalar    *coords;
3119   char            line[PETSC_MAX_PATH_LEN];
3120   PetscInt        dim = 3, cdim = 3, coordSize, v, c, d;
3121   PetscMPIInt     rank;
3122   int             snum, Nv, Nc;
3123   PetscErrorCode  ierr;
3124 
3125   PetscFunctionBegin;
3126   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3127   ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
3128   ierr = PetscViewerSetType(viewer, PETSCVIEWERASCII);CHKERRQ(ierr);
3129   ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
3130   ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
3131   if (!rank) {
3132     ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
3133     snum = sscanf(line, "%d %d", &Nc, &Nv);
3134     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3135   } else {
3136     Nc = Nv = 0;
3137   }
3138   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3139   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3140   ierr = DMPlexSetChart(*dm, 0, Nc+Nv);CHKERRQ(ierr);
3141   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
3142   ierr = DMSetCoordinateDim(*dm, cdim);CHKERRQ(ierr);
3143   /* Read topology */
3144   if (!rank) {
3145     PetscInt cone[8], corners = 8;
3146     int      vbuf[8], v;
3147 
3148     for (c = 0; c < Nc; ++c) {ierr = DMPlexSetConeSize(*dm, c, corners);CHKERRQ(ierr);}
3149     ierr = DMSetUp(*dm);CHKERRQ(ierr);
3150     for (c = 0; c < Nc; ++c) {
3151       ierr = PetscViewerRead(viewer, line, corners, NULL, PETSC_STRING);CHKERRQ(ierr);
3152       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]);
3153       if (snum != corners) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3154       for (v = 0; v < corners; ++v) cone[v] = vbuf[v] + Nc;
3155       /* Hexahedra are inverted */
3156       {
3157         PetscInt tmp = cone[1];
3158         cone[1] = cone[3];
3159         cone[3] = tmp;
3160       }
3161       ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
3162     }
3163   }
3164   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
3165   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
3166   /* Read coordinates */
3167   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
3168   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
3169   ierr = PetscSectionSetFieldComponents(coordSection, 0, cdim);CHKERRQ(ierr);
3170   ierr = PetscSectionSetChart(coordSection, Nc, Nc + Nv);CHKERRQ(ierr);
3171   for (v = Nc; v < Nc+Nv; ++v) {
3172     ierr = PetscSectionSetDof(coordSection, v, cdim);CHKERRQ(ierr);
3173     ierr = PetscSectionSetFieldDof(coordSection, v, 0, cdim);CHKERRQ(ierr);
3174   }
3175   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
3176   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
3177   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
3178   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
3179   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3180   ierr = VecSetBlockSize(coordinates, cdim);CHKERRQ(ierr);
3181   ierr = VecSetType(coordinates, VECSTANDARD);CHKERRQ(ierr);
3182   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3183   if (!rank) {
3184     double x[3];
3185     int    val;
3186 
3187     ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
3188     ierr = DMGetLabel(*dm, "marker", &marker);CHKERRQ(ierr);
3189     for (v = 0; v < Nv; ++v) {
3190       ierr = PetscViewerRead(viewer, line, 4, NULL, PETSC_STRING);CHKERRQ(ierr);
3191       snum = sscanf(line, "%lg %lg %lg %d", &x[0], &x[1], &x[2], &val);
3192       if (snum != 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
3193       for (d = 0; d < cdim; ++d) coords[v*cdim+d] = x[d];
3194       if (val) {ierr = DMLabelSetValue(marker, v+Nc, val);CHKERRQ(ierr);}
3195     }
3196   }
3197   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3198   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
3199   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
3200   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
3201   if (interpolate) {
3202     DM      idm;
3203     DMLabel bdlabel;
3204 
3205     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3206     ierr = DMDestroy(dm);CHKERRQ(ierr);
3207     *dm  = idm;
3208 
3209     ierr = DMGetLabel(*dm, "marker", &bdlabel);CHKERRQ(ierr);
3210     ierr = DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel);CHKERRQ(ierr);
3211     ierr = DMPlexLabelComplete(*dm, bdlabel);CHKERRQ(ierr);
3212   }
3213   PetscFunctionReturn(0);
3214 }
3215 
3216 /*@C
3217   DMPlexCreateFromFile - This takes a filename and produces a DM
3218 
3219   Input Parameters:
3220 + comm - The communicator
3221 . filename - A file name
3222 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
3223 
3224   Output Parameter:
3225 . dm - The DM
3226 
3227   Options Database Keys:
3228 . -dm_plex_create_from_hdf5_xdmf - use the PETSC_VIEWER_HDF5_XDMF format for reading HDF5
3229 
3230   Use -dm_plex_create_ prefix to pass options to the internal PetscViewer, e.g.
3231 $ -dm_plex_create_viewer_hdf5_collective
3232 
3233   Level: beginner
3234 
3235 .seealso: DMPlexCreateFromDAG(), DMPlexCreateFromCellList(), DMPlexCreate()
3236 @*/
3237 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
3238 {
3239   const char    *extGmsh    = ".msh";
3240   const char    *extGmsh2   = ".msh2";
3241   const char    *extGmsh4   = ".msh4";
3242   const char    *extCGNS    = ".cgns";
3243   const char    *extExodus  = ".exo";
3244   const char    *extGenesis = ".gen";
3245   const char    *extFluent  = ".cas";
3246   const char    *extHDF5    = ".h5";
3247   const char    *extMed     = ".med";
3248   const char    *extPLY     = ".ply";
3249   const char    *extCV      = ".dat";
3250   size_t         len;
3251   PetscBool      isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isMed, isPLY, isCV;
3252   PetscMPIInt    rank;
3253   PetscErrorCode ierr;
3254 
3255   PetscFunctionBegin;
3256   PetscValidCharPointer(filename, 2);
3257   PetscValidPointer(dm, 4);
3258   if (!DM_Plex_CreateFromFile) {ierr = PetscLogEventRegister("DMPlexCrFromFile",DM_CLASSID,&DM_Plex_CreateFromFile);}
3259   ierr = PetscLogEventBegin(DM_Plex_CreateFromFile,0,0,0,0);CHKERRQ(ierr);
3260   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3261   ierr = PetscStrlen(filename, &len);CHKERRQ(ierr);
3262   if (!len) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
3263   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGmsh,    4, &isGmsh);CHKERRQ(ierr);
3264   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extGmsh2,   5, &isGmsh2);CHKERRQ(ierr);
3265   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extGmsh4,   5, &isGmsh4);CHKERRQ(ierr);
3266   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extCGNS,    5, &isCGNS);CHKERRQ(ierr);
3267   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extExodus,  4, &isExodus);CHKERRQ(ierr);
3268   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGenesis, 4, &isGenesis);CHKERRQ(ierr);
3269   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extFluent,  4, &isFluent);CHKERRQ(ierr);
3270   ierr = PetscStrncmp(&filename[PetscMax(0,len-3)], extHDF5,    3, &isHDF5);CHKERRQ(ierr);
3271   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extMed,     4, &isMed);CHKERRQ(ierr);
3272   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extPLY,     4, &isPLY);CHKERRQ(ierr);
3273   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extCV,      4, &isCV);CHKERRQ(ierr);
3274   if (isGmsh || isGmsh2 || isGmsh4) {
3275     ierr = DMPlexCreateGmshFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3276   } else if (isCGNS) {
3277     ierr = DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3278   } else if (isExodus || isGenesis) {
3279     ierr = DMPlexCreateExodusFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3280   } else if (isFluent) {
3281     ierr = DMPlexCreateFluentFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3282   } else if (isHDF5) {
3283     PetscBool      load_hdf5_xdmf = PETSC_FALSE;
3284     PetscViewer viewer;
3285 
3286     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
3287     ierr = PetscStrncmp(&filename[PetscMax(0,len-8)], ".xdmf",  5, &load_hdf5_xdmf);CHKERRQ(ierr);
3288     ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &load_hdf5_xdmf, NULL);CHKERRQ(ierr);
3289     ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
3290     ierr = PetscViewerSetType(viewer, PETSCVIEWERHDF5);CHKERRQ(ierr);
3291     ierr = PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_");CHKERRQ(ierr);
3292     ierr = PetscViewerSetFromOptions(viewer);CHKERRQ(ierr);
3293     ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
3294     ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
3295     ierr = DMCreate(comm, dm);CHKERRQ(ierr);
3296     ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
3297     if (load_hdf5_xdmf) {ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF);CHKERRQ(ierr);}
3298     ierr = DMLoad(*dm, viewer);CHKERRQ(ierr);
3299     if (load_hdf5_xdmf) {ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);}
3300     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
3301 
3302     if (interpolate) {
3303       DM idm;
3304 
3305       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
3306       ierr = DMDestroy(dm);CHKERRQ(ierr);
3307       *dm  = idm;
3308     }
3309   } else if (isMed) {
3310     ierr = DMPlexCreateMedFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3311   } else if (isPLY) {
3312     ierr = DMPlexCreatePLYFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3313   } else if (isCV) {
3314     ierr = DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
3315   } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
3316   ierr = PetscLogEventEnd(DM_Plex_CreateFromFile,0,0,0,0);CHKERRQ(ierr);
3317   PetscFunctionReturn(0);
3318 }
3319 
3320 /*@
3321   DMPlexCreateReferenceCell - Create a DMPLEX with the appropriate FEM reference cell
3322 
3323   Collective
3324 
3325   Input Parameters:
3326 + comm    - The communicator
3327 . dim     - The spatial dimension
3328 - simplex - Flag for simplex, otherwise use a tensor-product cell
3329 
3330   Output Parameter:
3331 . refdm - The reference cell
3332 
3333   Level: intermediate
3334 
3335 .seealso:
3336 @*/
3337 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *refdm)
3338 {
3339   DM             rdm;
3340   Vec            coords;
3341   PetscErrorCode ierr;
3342 
3343   PetscFunctionBeginUser;
3344   ierr = DMCreate(comm, &rdm);CHKERRQ(ierr);
3345   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
3346   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
3347   switch (dim) {
3348   case 0:
3349   {
3350     PetscInt    numPoints[1]        = {1};
3351     PetscInt    coneSize[1]         = {0};
3352     PetscInt    cones[1]            = {0};
3353     PetscInt    coneOrientations[1] = {0};
3354     PetscScalar vertexCoords[1]     = {0.0};
3355 
3356     ierr = DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3357   }
3358   break;
3359   case 1:
3360   {
3361     PetscInt    numPoints[2]        = {2, 1};
3362     PetscInt    coneSize[3]         = {2, 0, 0};
3363     PetscInt    cones[2]            = {1, 2};
3364     PetscInt    coneOrientations[2] = {0, 0};
3365     PetscScalar vertexCoords[2]     = {-1.0,  1.0};
3366 
3367     ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3368   }
3369   break;
3370   case 2:
3371     if (simplex) {
3372       PetscInt    numPoints[2]        = {3, 1};
3373       PetscInt    coneSize[4]         = {3, 0, 0, 0};
3374       PetscInt    cones[3]            = {1, 2, 3};
3375       PetscInt    coneOrientations[3] = {0, 0, 0};
3376       PetscScalar vertexCoords[6]     = {-1.0, -1.0,  1.0, -1.0,  -1.0, 1.0};
3377 
3378       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3379     } else {
3380       PetscInt    numPoints[2]        = {4, 1};
3381       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3382       PetscInt    cones[4]            = {1, 2, 3, 4};
3383       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3384       PetscScalar vertexCoords[8]     = {-1.0, -1.0,  1.0, -1.0,  1.0, 1.0,  -1.0, 1.0};
3385 
3386       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3387     }
3388   break;
3389   case 3:
3390     if (simplex) {
3391       PetscInt    numPoints[2]        = {4, 1};
3392       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
3393       PetscInt    cones[4]            = {1, 3, 2, 4};
3394       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
3395       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};
3396 
3397       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3398     } else {
3399       PetscInt    numPoints[2]        = {8, 1};
3400       PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
3401       PetscInt    cones[8]            = {1, 4, 3, 2, 5, 6, 7, 8};
3402       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
3403       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,
3404                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0, 1.0,  1.0,  -1.0, 1.0,  1.0};
3405 
3406       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
3407     }
3408   break;
3409   default:
3410     SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Cannot create reference cell for dimension %d", dim);
3411   }
3412   ierr = DMPlexInterpolate(rdm, refdm);CHKERRQ(ierr);
3413   if (rdm->coordinateDM) {
3414     DM           ncdm;
3415     PetscSection cs;
3416     PetscInt     pEnd = -1;
3417 
3418     ierr = DMGetLocalSection(rdm->coordinateDM, &cs);CHKERRQ(ierr);
3419     if (cs) {ierr = PetscSectionGetChart(cs, NULL, &pEnd);CHKERRQ(ierr);}
3420     if (pEnd >= 0) {
3421       ierr = DMClone(*refdm, &ncdm);CHKERRQ(ierr);
3422       ierr = DMCopyDisc(rdm->coordinateDM, ncdm);CHKERRQ(ierr);
3423       ierr = DMSetLocalSection(ncdm, cs);CHKERRQ(ierr);
3424       ierr = DMSetCoordinateDM(*refdm, ncdm);CHKERRQ(ierr);
3425       ierr = DMDestroy(&ncdm);CHKERRQ(ierr);
3426     }
3427   }
3428   ierr = DMGetCoordinatesLocal(rdm, &coords);CHKERRQ(ierr);
3429   if (coords) {
3430     ierr = DMSetCoordinatesLocal(*refdm, coords);CHKERRQ(ierr);
3431   } else {
3432     ierr = DMGetCoordinates(rdm, &coords);CHKERRQ(ierr);
3433     if (coords) {ierr = DMSetCoordinates(*refdm, coords);CHKERRQ(ierr);}
3434   }
3435   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
3436   PetscFunctionReturn(0);
3437 }
3438