xref: /petsc/src/dm/impls/plex/plexcreate.c (revision 42c1443f0aee21f8b2e6ef7e4664d225a30cb2a7)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/
3 #include <petscdmda.h>
4 #include <petscsf.h>
5 
6 /*@
7   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.
8 
9   Collective on MPI_Comm
10 
11   Input Parameters:
12 + comm - The communicator for the DM object
13 . dim - The spatial dimension
14 . simplex - Flag for simplicial cells, otherwise they are tensor product cells
15 . interpolate - Flag to create intermediate mesh pieces (edges, faces)
16 . refinementUniform - Flag for uniform parallel refinement
17 - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell
18 
19   Output Parameter:
20 . dm  - The DM object
21 
22   Level: beginner
23 
24 .keywords: DM, create
25 .seealso: DMSetType(), DMCreate()
26 @*/
27 PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscBool refinementUniform, PetscReal refinementLimit, DM *newdm)
28 {
29   DM             dm;
30   PetscInt       p;
31   PetscMPIInt    rank;
32   PetscErrorCode ierr;
33 
34   PetscFunctionBegin;
35   ierr = DMCreate(comm, &dm);CHKERRQ(ierr);
36   ierr = DMSetType(dm, DMPLEX);CHKERRQ(ierr);
37   ierr = DMSetDimension(dm, dim);CHKERRQ(ierr);
38   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
39   switch (dim) {
40   case 2:
41     if (simplex) {ierr = PetscObjectSetName((PetscObject) dm, "triangular");CHKERRQ(ierr);}
42     else         {ierr = PetscObjectSetName((PetscObject) dm, "quadrilateral");CHKERRQ(ierr);}
43     break;
44   case 3:
45     if (simplex) {ierr = PetscObjectSetName((PetscObject) dm, "tetrahedral");CHKERRQ(ierr);}
46     else         {ierr = PetscObjectSetName((PetscObject) dm, "hexahedral");CHKERRQ(ierr);}
47     break;
48   default:
49     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %d", dim);
50   }
51   if (rank) {
52     PetscInt numPoints[2] = {0, 0};
53     ierr = DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
54   } else {
55     switch (dim) {
56     case 2:
57       if (simplex) {
58         PetscInt    numPoints[2]        = {4, 2};
59         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
60         PetscInt    cones[6]            = {2, 3, 4,  5, 4, 3};
61         PetscInt    coneOrientations[6] = {0, 0, 0,  0, 0, 0};
62         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
63         PetscInt    markerPoints[8]     = {2, 1, 3, 1, 4, 1, 5, 1};
64 
65         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
66         for (p = 0; p < 4; ++p) {ierr = DMSetLabelValue(dm, "marker", markerPoints[p*2], markerPoints[p*2+1]);CHKERRQ(ierr);}
67       } else {
68         PetscInt    numPoints[2]        = {6, 2};
69         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
70         PetscInt    cones[8]            = {2, 3, 4, 5,  3, 6, 7, 4};
71         PetscInt    coneOrientations[8] = {0, 0, 0, 0,  0, 0, 0, 0};
72         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};
73 
74         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
75       }
76       break;
77     case 3:
78       if (simplex) {
79         PetscInt    numPoints[2]        = {5, 2};
80         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
81         PetscInt    cones[8]            = {4, 3, 5, 2,  5, 3, 4, 6};
82         PetscInt    coneOrientations[8] = {0, 0, 0, 0,  0, 0, 0, 0};
83         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};
84         PetscInt    markerPoints[10]    = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1};
85 
86         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
87         for (p = 0; p < 5; ++p) {ierr = DMSetLabelValue(dm, "marker", markerPoints[p*2], markerPoints[p*2+1]);CHKERRQ(ierr);}
88       } else {
89         PetscInt    numPoints[2]         = {12, 2};
90         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
91         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9,  5, 4, 10, 11, 7, 12, 13, 8};
92         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0,  0, 0,  0,  0, 0,  0,  0, 0};
93         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,
94                                             -1.0, -0.5,  0.5,   0.0, -0.5,  0.5,  0.0,  0.5,  0.5,  -1.0,  0.5,  0.5,
95                                              1.0,  0.5, -0.5,   1.0, -0.5, -0.5,  1.0, -0.5,  0.5,   1.0,  0.5,  0.5};
96 
97         ierr = DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
98       }
99       break;
100     default:
101       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %d", dim);
102     }
103   }
104   *newdm = dm;
105   if (refinementLimit > 0.0) {
106     DM rdm;
107     const char *name;
108 
109     ierr = DMPlexSetRefinementUniform(*newdm, PETSC_FALSE);CHKERRQ(ierr);
110     ierr = DMPlexSetRefinementLimit(*newdm, refinementLimit);CHKERRQ(ierr);
111     ierr = DMRefine(*newdm, comm, &rdm);CHKERRQ(ierr);
112     ierr = PetscObjectGetName((PetscObject) *newdm, &name);CHKERRQ(ierr);
113     ierr = PetscObjectSetName((PetscObject)    rdm,  name);CHKERRQ(ierr);
114     ierr = DMDestroy(newdm);CHKERRQ(ierr);
115     *newdm = rdm;
116   }
117   if (interpolate) {
118     DM idm = NULL;
119     const char *name;
120 
121     ierr = DMPlexInterpolate(*newdm, &idm);CHKERRQ(ierr);
122     ierr = PetscObjectGetName((PetscObject) *newdm, &name);CHKERRQ(ierr);
123     ierr = PetscObjectSetName((PetscObject)    idm,  name);CHKERRQ(ierr);
124     ierr = DMPlexCopyCoordinates(*newdm, idm);CHKERRQ(ierr);
125     ierr = DMCopyLabels(*newdm, idm);CHKERRQ(ierr);
126     ierr = DMDestroy(newdm);CHKERRQ(ierr);
127     *newdm = idm;
128   }
129   {
130     DM refinedMesh     = NULL;
131     DM distributedMesh = NULL;
132 
133     /* Distribute mesh over processes */
134     ierr = DMPlexDistribute(*newdm, 0, NULL, &distributedMesh);CHKERRQ(ierr);
135     if (distributedMesh) {
136       ierr = DMDestroy(newdm);CHKERRQ(ierr);
137       *newdm = distributedMesh;
138     }
139     if (refinementUniform) {
140       ierr = DMPlexSetRefinementUniform(*newdm, refinementUniform);CHKERRQ(ierr);
141       ierr = DMRefine(*newdm, comm, &refinedMesh);CHKERRQ(ierr);
142       if (refinedMesh) {
143         ierr = DMDestroy(newdm);CHKERRQ(ierr);
144         *newdm = refinedMesh;
145       }
146     }
147   }
148   PetscFunctionReturn(0);
149 }
150 
151 /*@
152   DMPlexCreateSquareBoundary - Creates a 1D mesh the is the boundary of a square lattice.
153 
154   Collective on MPI_Comm
155 
156   Input Parameters:
157 + comm  - The communicator for the DM object
158 . lower - The lower left corner coordinates
159 . upper - The upper right corner coordinates
160 - edges - The number of cells in each direction
161 
162   Output Parameter:
163 . dm  - The DM object
164 
165   Note: Here is the numbering returned for 2 cells in each direction:
166 $ 18--5-17--4--16
167 $  |     |     |
168 $  6    10     3
169 $  |     |     |
170 $ 19-11-20--9--15
171 $  |     |     |
172 $  7     8     2
173 $  |     |     |
174 $ 12--0-13--1--14
175 
176   Level: beginner
177 
178 .keywords: DM, create
179 .seealso: DMPlexCreateBoxMesh(), DMPlexCreateCubeBoundary(), DMSetType(), DMCreate()
180 @*/
181 PetscErrorCode DMPlexCreateSquareBoundary(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
182 {
183   const PetscInt numVertices    = (edges[0]+1)*(edges[1]+1);
184   const PetscInt numEdges       = edges[0]*(edges[1]+1) + (edges[0]+1)*edges[1];
185   PetscInt       markerTop      = 1;
186   PetscInt       markerBottom   = 1;
187   PetscInt       markerRight    = 1;
188   PetscInt       markerLeft     = 1;
189   PetscBool      markerSeparate = PETSC_FALSE;
190   Vec            coordinates;
191   PetscSection   coordSection;
192   PetscScalar    *coords;
193   PetscInt       coordSize;
194   PetscMPIInt    rank;
195   PetscInt       v, vx, vy;
196   PetscErrorCode ierr;
197 
198   PetscFunctionBegin;
199   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL);CHKERRQ(ierr);
200   if (markerSeparate) {
201     markerTop    = 3;
202     markerBottom = 1;
203     markerRight  = 2;
204     markerLeft   = 4;
205   }
206   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
207   if (!rank) {
208     PetscInt e, ex, ey;
209 
210     ierr = DMPlexSetChart(dm, 0, numEdges+numVertices);CHKERRQ(ierr);
211     for (e = 0; e < numEdges; ++e) {
212       ierr = DMPlexSetConeSize(dm, e, 2);CHKERRQ(ierr);
213     }
214     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
215     for (vx = 0; vx <= edges[0]; vx++) {
216       for (ey = 0; ey < edges[1]; ey++) {
217         PetscInt edge   = vx*edges[1] + ey + edges[0]*(edges[1]+1);
218         PetscInt vertex = ey*(edges[0]+1) + vx + numEdges;
219         PetscInt cone[2];
220 
221         cone[0] = vertex; cone[1] = vertex+edges[0]+1;
222         ierr    = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
223         if (vx == edges[0]) {
224           ierr = DMSetLabelValue(dm, "marker", edge,    markerRight);CHKERRQ(ierr);
225           ierr = DMSetLabelValue(dm, "marker", cone[0], markerRight);CHKERRQ(ierr);
226           if (ey == edges[1]-1) {
227             ierr = DMSetLabelValue(dm, "marker", cone[1], markerRight);CHKERRQ(ierr);
228             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerRight);CHKERRQ(ierr);
229           }
230         } else if (vx == 0) {
231           ierr = DMSetLabelValue(dm, "marker", edge,    markerLeft);CHKERRQ(ierr);
232           ierr = DMSetLabelValue(dm, "marker", cone[0], markerLeft);CHKERRQ(ierr);
233           if (ey == edges[1]-1) {
234             ierr = DMSetLabelValue(dm, "marker", cone[1], markerLeft);CHKERRQ(ierr);
235             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft);CHKERRQ(ierr);
236           }
237         }
238       }
239     }
240     for (vy = 0; vy <= edges[1]; vy++) {
241       for (ex = 0; ex < edges[0]; ex++) {
242         PetscInt edge   = vy*edges[0]     + ex;
243         PetscInt vertex = vy*(edges[0]+1) + ex + numEdges;
244         PetscInt cone[2];
245 
246         cone[0] = vertex; cone[1] = vertex+1;
247         ierr    = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
248         if (vy == edges[1]) {
249           ierr = DMSetLabelValue(dm, "marker", edge,    markerTop);CHKERRQ(ierr);
250           ierr = DMSetLabelValue(dm, "marker", cone[0], markerTop);CHKERRQ(ierr);
251           if (ex == edges[0]-1) {
252             ierr = DMSetLabelValue(dm, "marker", cone[1], markerTop);CHKERRQ(ierr);
253             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerTop);CHKERRQ(ierr);
254           }
255         } else if (vy == 0) {
256           ierr = DMSetLabelValue(dm, "marker", edge,    markerBottom);CHKERRQ(ierr);
257           ierr = DMSetLabelValue(dm, "marker", cone[0], markerBottom);CHKERRQ(ierr);
258           if (ex == edges[0]-1) {
259             ierr = DMSetLabelValue(dm, "marker", cone[1], markerBottom);CHKERRQ(ierr);
260             ierr = DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom);CHKERRQ(ierr);
261           }
262         }
263       }
264     }
265   }
266   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
267   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
268   /* Build coordinates */
269   ierr = DMSetCoordinateDim(dm, 2);CHKERRQ(ierr);
270   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
271   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
272   ierr = PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices);CHKERRQ(ierr);
273   ierr = PetscSectionSetFieldComponents(coordSection, 0, 2);CHKERRQ(ierr);
274   for (v = numEdges; v < numEdges+numVertices; ++v) {
275     ierr = PetscSectionSetDof(coordSection, v, 2);CHKERRQ(ierr);
276     ierr = PetscSectionSetFieldDof(coordSection, v, 0, 2);CHKERRQ(ierr);
277   }
278   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
279   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
280   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
281   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
282   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
283   ierr = VecSetBlockSize(coordinates, 2);CHKERRQ(ierr);
284   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
285   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
286   for (vy = 0; vy <= edges[1]; ++vy) {
287     for (vx = 0; vx <= edges[0]; ++vx) {
288       coords[(vy*(edges[0]+1)+vx)*2+0] = lower[0] + ((upper[0] - lower[0])/edges[0])*vx;
289       coords[(vy*(edges[0]+1)+vx)*2+1] = lower[1] + ((upper[1] - lower[1])/edges[1])*vy;
290     }
291   }
292   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
293   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
294   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
295   PetscFunctionReturn(0);
296 }
297 
298 /*@
299   DMPlexCreateCubeBoundary - Creates a 2D mesh the is the boundary of a cubic lattice.
300 
301   Collective on MPI_Comm
302 
303   Input Parameters:
304 + comm  - The communicator for the DM object
305 . lower - The lower left front corner coordinates
306 . upper - The upper right back corner coordinates
307 - edges - The number of cells in each direction
308 
309   Output Parameter:
310 . dm  - The DM object
311 
312   Level: beginner
313 
314 .keywords: DM, create
315 .seealso: DMPlexCreateBoxMesh(), DMPlexCreateSquareBoundary(), DMSetType(), DMCreate()
316 @*/
317 PetscErrorCode DMPlexCreateCubeBoundary(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
318 {
319   PetscInt       vertices[3], numVertices;
320   PetscInt       numFaces    = 2*faces[0]*faces[1] + 2*faces[1]*faces[2] + 2*faces[0]*faces[2];
321   Vec            coordinates;
322   PetscSection   coordSection;
323   PetscScalar    *coords;
324   PetscInt       coordSize;
325   PetscMPIInt    rank;
326   PetscInt       v, vx, vy, vz;
327   PetscInt       voffset, iface=0, cone[4];
328   PetscErrorCode ierr;
329 
330   PetscFunctionBegin;
331   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");
332   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
333   vertices[0] = faces[0]+1; vertices[1] = faces[1]+1; vertices[2] = faces[2]+1;
334   numVertices = vertices[0]*vertices[1]*vertices[2];
335   if (!rank) {
336     PetscInt f;
337 
338     ierr = DMPlexSetChart(dm, 0, numFaces+numVertices);CHKERRQ(ierr);
339     for (f = 0; f < numFaces; ++f) {
340       ierr = DMPlexSetConeSize(dm, f, 4);CHKERRQ(ierr);
341     }
342     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
343     for (v = 0; v < numFaces+numVertices; ++v) {
344       ierr = DMSetLabelValue(dm, "marker", v, 1);CHKERRQ(ierr);
345     }
346 
347     /* Side 0 (Top) */
348     for (vy = 0; vy < faces[1]; vy++) {
349       for (vx = 0; vx < faces[0]; vx++) {
350         voffset = numFaces + vertices[0]*vertices[1]*(vertices[2]-1) + vy*vertices[0] + vx;
351         cone[0] = voffset; cone[1] = voffset+1; cone[2] = voffset+vertices[0]+1; cone[3] = voffset+vertices[0];
352         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
353         iface++;
354       }
355     }
356 
357     /* Side 1 (Bottom) */
358     for (vy = 0; vy < faces[1]; vy++) {
359       for (vx = 0; vx < faces[0]; vx++) {
360         voffset = numFaces + vy*(faces[0]+1) + vx;
361         cone[0] = voffset+1; cone[1] = voffset; cone[2] = voffset+vertices[0]; cone[3] = voffset+vertices[0]+1;
362         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
363         iface++;
364       }
365     }
366 
367     /* Side 2 (Front) */
368     for (vz = 0; vz < faces[2]; vz++) {
369       for (vx = 0; vx < faces[0]; vx++) {
370         voffset = numFaces + vz*vertices[0]*vertices[1] + vx;
371         cone[0] = voffset; cone[1] = voffset+1; cone[2] = voffset+vertices[0]*vertices[1]+1; cone[3] = voffset+vertices[0]*vertices[1];
372         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
373         iface++;
374       }
375     }
376 
377     /* Side 3 (Back) */
378     for (vz = 0; vz < faces[2]; vz++) {
379       for (vx = 0; vx < faces[0]; vx++) {
380         voffset = numFaces + vz*vertices[0]*vertices[1] + vertices[0]*(vertices[1]-1) + vx;
381         cone[0] = voffset+vertices[0]*vertices[1]; cone[1] = voffset+vertices[0]*vertices[1]+1;
382         cone[2] = voffset+1; cone[3] = voffset;
383         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
384         iface++;
385       }
386     }
387 
388     /* Side 4 (Left) */
389     for (vz = 0; vz < faces[2]; vz++) {
390       for (vy = 0; vy < faces[1]; vy++) {
391         voffset = numFaces + vz*vertices[0]*vertices[1] + vy*vertices[0];
392         cone[0] = voffset; cone[1] = voffset+vertices[0]*vertices[1];
393         cone[2] = voffset+vertices[0]*vertices[1]+vertices[0]; cone[3] = voffset+vertices[0];
394         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
395         iface++;
396       }
397     }
398 
399     /* Side 5 (Right) */
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] + faces[0];
403         cone[0] = voffset+vertices[0]*vertices[1]; cone[1] = voffset;
404         cone[2] = voffset+vertices[0]; cone[3] = voffset+vertices[0]*vertices[1]+vertices[0];
405         ierr    = DMPlexSetCone(dm, iface, cone);CHKERRQ(ierr);
406         iface++;
407       }
408     }
409   }
410   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
411   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
412   /* Build coordinates */
413   ierr = DMSetCoordinateDim(dm, 3);CHKERRQ(ierr);
414   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
415   ierr = PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices);CHKERRQ(ierr);
416   for (v = numFaces; v < numFaces+numVertices; ++v) {
417     ierr = PetscSectionSetDof(coordSection, v, 3);CHKERRQ(ierr);
418   }
419   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
420   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
421   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
422   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
423   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
424   ierr = VecSetBlockSize(coordinates, 3);CHKERRQ(ierr);
425   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
426   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
427   for (vz = 0; vz <= faces[2]; ++vz) {
428     for (vy = 0; vy <= faces[1]; ++vy) {
429       for (vx = 0; vx <= faces[0]; ++vx) {
430         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+0] = lower[0] + ((upper[0] - lower[0])/faces[0])*vx;
431         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+1] = lower[1] + ((upper[1] - lower[1])/faces[1])*vy;
432         coords[((vz*(faces[1]+1)+vy)*(faces[0]+1)+vx)*3+2] = lower[2] + ((upper[2] - lower[2])/faces[2])*vz;
433       }
434     }
435   }
436   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
437   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
438   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
439   PetscFunctionReturn(0);
440 }
441 
442 /*@C
443   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices.
444 
445   Collective on MPI_Comm
446 
447   Input Parameters:
448 + comm - The communicator for the DM object
449 . dim - The spatial dimension
450 . faces - Number of faces per dimension, or NULL for (2, 2) in 2D and (1, 1, 1) in 3D
451 . lower - The lower left corner, or NULL for (0, 0, 0)
452 . upper - The upper right corner, or NULL for (1, 1, 1)
453 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
454 
455   Output Parameter:
456 . dm  - The DM object
457 
458   Level: beginner
459 
460 .keywords: DM, create
461 .seealso: DMPlexCreateHexBoxMesh(), DMSetType(), DMCreate()
462 @*/
463 PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
464 {
465   DM             boundary;
466   PetscReal      low[3] = {lower ? lower[0] : 0.0, lower ? lower[1] : 0.0, lower ? lower[2] : 0.0};
467   PetscReal      upp[3] = {upper ? upper[0] : 1.0, upper ? upper[1] : 1.0, upper ? upper[2] : 1.0};
468   PetscInt       fac[3] = {faces ? faces[0] : 4-dim, faces ? faces[1] : 4-dim, faces ? faces[2] : 4-dim};
469   PetscErrorCode ierr;
470 
471   PetscFunctionBegin;
472   PetscValidPointer(dm, 4);
473   ierr = DMCreate(comm, &boundary);CHKERRQ(ierr);
474   PetscValidLogicalCollectiveInt(boundary,dim,2);
475   ierr = DMSetType(boundary, DMPLEX);CHKERRQ(ierr);
476   ierr = DMSetDimension(boundary, dim-1);CHKERRQ(ierr);
477   ierr = DMSetCoordinateDim(boundary, dim);CHKERRQ(ierr);
478   switch (dim) {
479   case 2: ierr = DMPlexCreateSquareBoundary(boundary, low, upp, fac);CHKERRQ(ierr);break;
480   case 3: ierr = DMPlexCreateCubeBoundary(boundary, low, upp, fac);CHKERRQ(ierr);break;
481   default: SETERRQ1(comm, PETSC_ERR_SUP, "Dimension not supported: %d", dim);
482   }
483   ierr = DMPlexGenerate(boundary, NULL, interpolate, dm);CHKERRQ(ierr);
484   ierr = DMDestroy(&boundary);CHKERRQ(ierr);
485   PetscFunctionReturn(0);
486 }
487 
488 static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
489 {
490   DMLabel        cutLabel = NULL;
491   PetscInt       markerTop      = 1, faceMarkerTop      = 1;
492   PetscInt       markerBottom   = 1, faceMarkerBottom   = 1;
493   PetscInt       markerFront    = 1, faceMarkerFront    = 1;
494   PetscInt       markerBack     = 1, faceMarkerBack     = 1;
495   PetscInt       markerRight    = 1, faceMarkerRight    = 1;
496   PetscInt       markerLeft     = 1, faceMarkerLeft     = 1;
497   PetscInt       dim;
498   PetscBool      markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
499   PetscMPIInt    rank;
500   PetscErrorCode ierr;
501 
502   PetscFunctionBegin;
503   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
504   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
505   ierr = DMCreateLabel(dm,"marker");CHKERRQ(ierr);
506   ierr = DMCreateLabel(dm,"Face Sets");CHKERRQ(ierr);
507   if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ||
508       bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ||
509       bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) {
510     ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL);CHKERRQ(ierr);
511     if (cutMarker) {ierr = DMCreateLabel(dm, "periodic_cut");CHKERRQ(ierr); ierr = DMGetLabel(dm, "periodic_cut", &cutLabel);CHKERRQ(ierr);}
512   }
513   switch (dim) {
514   case 2:
515     faceMarkerTop    = 3;
516     faceMarkerBottom = 1;
517     faceMarkerRight  = 2;
518     faceMarkerLeft   = 4;
519     break;
520   case 3:
521     faceMarkerBottom = 1;
522     faceMarkerTop    = 2;
523     faceMarkerFront  = 3;
524     faceMarkerBack   = 4;
525     faceMarkerRight  = 5;
526     faceMarkerLeft   = 6;
527     break;
528   default:
529     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Dimension %d not supported",dim);
530     break;
531   }
532   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL);CHKERRQ(ierr);
533   if (markerSeparate) {
534     markerBottom = faceMarkerBottom;
535     markerTop    = faceMarkerTop;
536     markerFront  = faceMarkerFront;
537     markerBack   = faceMarkerBack;
538     markerRight  = faceMarkerRight;
539     markerLeft   = faceMarkerLeft;
540   }
541   {
542     const PetscInt numXEdges    = !rank ? edges[0] : 0;
543     const PetscInt numYEdges    = !rank ? edges[1] : 0;
544     const PetscInt numZEdges    = !rank ? edges[2] : 0;
545     const PetscInt numXVertices = !rank ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0]+1) : 0;
546     const PetscInt numYVertices = !rank ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1]+1) : 0;
547     const PetscInt numZVertices = !rank ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2]+1) : 0;
548     const PetscInt numCells     = numXEdges*numYEdges*numZEdges;
549     const PetscInt numXFaces    = numYEdges*numZEdges;
550     const PetscInt numYFaces    = numXEdges*numZEdges;
551     const PetscInt numZFaces    = numXEdges*numYEdges;
552     const PetscInt numTotXFaces = numXVertices*numXFaces;
553     const PetscInt numTotYFaces = numYVertices*numYFaces;
554     const PetscInt numTotZFaces = numZVertices*numZFaces;
555     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
556     const PetscInt numTotXEdges = numXEdges*numYVertices*numZVertices;
557     const PetscInt numTotYEdges = numYEdges*numXVertices*numZVertices;
558     const PetscInt numTotZEdges = numZEdges*numXVertices*numYVertices;
559     const PetscInt numVertices  = numXVertices*numYVertices*numZVertices;
560     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
561     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
562     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
563     const PetscInt firstYFace   = firstXFace + numTotXFaces;
564     const PetscInt firstZFace   = firstYFace + numTotYFaces;
565     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
566     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
567     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
568     Vec            coordinates;
569     PetscSection   coordSection;
570     PetscScalar   *coords;
571     PetscInt       coordSize;
572     PetscInt       v, vx, vy, vz;
573     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;
574 
575     ierr = DMPlexSetChart(dm, 0, numCells+numFaces+numEdges+numVertices);CHKERRQ(ierr);
576     for (c = 0; c < numCells; c++) {
577       ierr = DMPlexSetConeSize(dm, c, 6);CHKERRQ(ierr);
578     }
579     for (f = firstXFace; f < firstXFace+numFaces; ++f) {
580       ierr = DMPlexSetConeSize(dm, f, 4);CHKERRQ(ierr);
581     }
582     for (e = firstXEdge; e < firstXEdge+numEdges; ++e) {
583       ierr = DMPlexSetConeSize(dm, e, 2);CHKERRQ(ierr);
584     }
585     ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
586     /* Build cells */
587     for (fz = 0; fz < numZEdges; ++fz) {
588       for (fy = 0; fy < numYEdges; ++fy) {
589         for (fx = 0; fx < numXEdges; ++fx) {
590           PetscInt cell    = (fz*numYEdges + fy)*numXEdges + fx;
591           PetscInt faceB   = firstZFace + (fy*numXEdges+fx)*numZVertices +   fz;
592           PetscInt faceT   = firstZFace + (fy*numXEdges+fx)*numZVertices + ((fz+1)%numZVertices);
593           PetscInt faceF   = firstYFace + (fz*numXEdges+fx)*numYVertices +   fy;
594           PetscInt faceK   = firstYFace + (fz*numXEdges+fx)*numYVertices + ((fy+1)%numYVertices);
595           PetscInt faceL   = firstXFace + (fz*numYEdges+fy)*numXVertices +   fx;
596           PetscInt faceR   = firstXFace + (fz*numYEdges+fy)*numXVertices + ((fx+1)%numXVertices);
597                             /* B,  T,  F,  K,  R,  L */
598           PetscInt ornt[6] = {-4,  0,  0, -1,  0, -4}; /* ??? */
599           PetscInt cone[6];
600 
601           /* no boundary twisting in 3D */
602           cone[0] = faceB; cone[1] = faceT; cone[2] = faceF; cone[3] = faceK; cone[4] = faceR; cone[5] = faceL;
603           ierr    = DMPlexSetCone(dm, cell, cone);CHKERRQ(ierr);
604           ierr    = DMPlexSetConeOrientation(dm, cell, ornt);CHKERRQ(ierr);
605           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
606           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
607           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, cell, 2);CHKERRQ(ierr);}
608         }
609       }
610     }
611     /* Build x faces */
612     for (fz = 0; fz < numZEdges; ++fz) {
613       for (fy = 0; fy < numYEdges; ++fy) {
614         for (fx = 0; fx < numXVertices; ++fx) {
615           PetscInt face    = firstXFace + (fz*numYEdges+fy)*numXVertices + fx;
616           PetscInt edgeL   = firstZEdge + (  fy*                 numXVertices+fx)*numZEdges + fz;
617           PetscInt edgeR   = firstZEdge + (((fy+1)%numYVertices)*numXVertices+fx)*numZEdges + fz;
618           PetscInt edgeB   = firstYEdge + (  fz*                 numXVertices+fx)*numYEdges + fy;
619           PetscInt edgeT   = firstYEdge + (((fz+1)%numZVertices)*numXVertices+fx)*numYEdges + fy;
620           PetscInt ornt[4] = {0, 0, -2, -2};
621           PetscInt cone[4];
622 
623           if (dim == 3) {
624             /* markers */
625             if (bdX != DM_BOUNDARY_PERIODIC) {
626               if (fx == numXVertices-1) {
627                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight);CHKERRQ(ierr);
628                 ierr = DMSetLabelValue(dm, "marker", face, markerRight);CHKERRQ(ierr);
629               }
630               else if (fx == 0) {
631                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft);CHKERRQ(ierr);
632                 ierr = DMSetLabelValue(dm, "marker", face, markerLeft);CHKERRQ(ierr);
633               }
634             }
635           }
636           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
637           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
638           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
639         }
640       }
641     }
642     /* Build y faces */
643     for (fz = 0; fz < numZEdges; ++fz) {
644       for (fx = 0; fx < numXEdges; ++fx) {
645         for (fy = 0; fy < numYVertices; ++fy) {
646           PetscInt face    = firstYFace + (fz*numXEdges+fx)*numYVertices + fy;
647           PetscInt edgeL   = firstZEdge + (fy*numXVertices+  fx                 )*numZEdges + fz;
648           PetscInt edgeR   = firstZEdge + (fy*numXVertices+((fx+1)%numXVertices))*numZEdges + fz;
649           PetscInt edgeB   = firstXEdge + (  fz                 *numYVertices+fy)*numXEdges + fx;
650           PetscInt edgeT   = firstXEdge + (((fz+1)%numZVertices)*numYVertices+fy)*numXEdges + fx;
651           PetscInt ornt[4] = {0, 0, -2, -2};
652           PetscInt cone[4];
653 
654           if (dim == 3) {
655             /* markers */
656             if (bdY != DM_BOUNDARY_PERIODIC) {
657               if (fy == numYVertices-1) {
658                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack);CHKERRQ(ierr);
659                 ierr = DMSetLabelValue(dm, "marker", face, markerBack);CHKERRQ(ierr);
660               }
661               else if (fy == 0) {
662                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront);CHKERRQ(ierr);
663                 ierr = DMSetLabelValue(dm, "marker", face, markerFront);CHKERRQ(ierr);
664               }
665             }
666           }
667           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
668           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
669           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
670         }
671       }
672     }
673     /* Build z faces */
674     for (fy = 0; fy < numYEdges; ++fy) {
675       for (fx = 0; fx < numXEdges; ++fx) {
676         for (fz = 0; fz < numZVertices; fz++) {
677           PetscInt face    = firstZFace + (fy*numXEdges+fx)*numZVertices + fz;
678           PetscInt edgeL   = firstYEdge + (fz*numXVertices+  fx                 )*numYEdges + fy;
679           PetscInt edgeR   = firstYEdge + (fz*numXVertices+((fx+1)%numXVertices))*numYEdges + fy;
680           PetscInt edgeB   = firstXEdge + (fz*numYVertices+  fy                 )*numXEdges + fx;
681           PetscInt edgeT   = firstXEdge + (fz*numYVertices+((fy+1)%numYVertices))*numXEdges + fx;
682           PetscInt ornt[4] = {0, 0, -2, -2};
683           PetscInt cone[4];
684 
685           if (dim == 2) {
686             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges-1) {edgeR += numYEdges-1-2*fy; ornt[1] = -2;}
687             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges-1) {edgeT += numXEdges-1-2*fx; ornt[2] =  0;}
688             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, face, 2);CHKERRQ(ierr);}
689             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges-1 && cutLabel) {ierr = DMLabelSetValue(cutLabel, face, 2);CHKERRQ(ierr);}
690           } else {
691             /* markers */
692             if (bdZ != DM_BOUNDARY_PERIODIC) {
693               if (fz == numZVertices-1) {
694                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop);CHKERRQ(ierr);
695                 ierr = DMSetLabelValue(dm, "marker", face, markerTop);CHKERRQ(ierr);
696               }
697               else if (fz == 0) {
698                 ierr = DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom);CHKERRQ(ierr);
699                 ierr = DMSetLabelValue(dm, "marker", face, markerBottom);CHKERRQ(ierr);
700               }
701             }
702           }
703           cone[0] = edgeB; cone[1] = edgeR; cone[2] = edgeT; cone[3] = edgeL;
704           ierr    = DMPlexSetCone(dm, face, cone);CHKERRQ(ierr);
705           ierr    = DMPlexSetConeOrientation(dm, face, ornt);CHKERRQ(ierr);
706         }
707       }
708     }
709     /* Build Z edges*/
710     for (vy = 0; vy < numYVertices; vy++) {
711       for (vx = 0; vx < numXVertices; vx++) {
712         for (ez = 0; ez < numZEdges; ez++) {
713           const PetscInt edge    = firstZEdge  + (vy*numXVertices+vx)*numZEdges + ez;
714           const PetscInt vertexB = firstVertex + (  ez                 *numYVertices+vy)*numXVertices + vx;
715           const PetscInt vertexT = firstVertex + (((ez+1)%numZVertices)*numYVertices+vy)*numXVertices + vx;
716           PetscInt       cone[2];
717 
718           if (dim == 3) {
719             if (bdX != DM_BOUNDARY_PERIODIC) {
720               if (vx == numXVertices-1) {
721                 ierr = DMSetLabelValue(dm, "marker", edge, markerRight);CHKERRQ(ierr);
722               }
723               else if (vx == 0) {
724                 ierr = DMSetLabelValue(dm, "marker", edge, markerLeft);CHKERRQ(ierr);
725               }
726             }
727             if (bdY != DM_BOUNDARY_PERIODIC) {
728               if (vy == numYVertices-1) {
729                 ierr = DMSetLabelValue(dm, "marker", edge, markerBack);CHKERRQ(ierr);
730               }
731               else if (vy == 0) {
732                 ierr = DMSetLabelValue(dm, "marker", edge, markerFront);CHKERRQ(ierr);
733               }
734             }
735           }
736           cone[0] = vertexB; cone[1] = vertexT;
737           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
738         }
739       }
740     }
741     /* Build Y edges*/
742     for (vz = 0; vz < numZVertices; vz++) {
743       for (vx = 0; vx < numXVertices; vx++) {
744         for (ey = 0; ey < numYEdges; ey++) {
745           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges-1) ? (numXVertices-vx-1) : (vz*numYVertices+((ey+1)%numYVertices))*numXVertices + vx;
746           const PetscInt edge    = firstYEdge  + (vz*numXVertices+vx)*numYEdges + ey;
747           const PetscInt vertexF = firstVertex + (vz*numYVertices+ey)*numXVertices + vx;
748           const PetscInt vertexK = firstVertex + nextv;
749           PetscInt       cone[2];
750 
751           cone[0] = vertexF; cone[1] = vertexK;
752           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
753           if (dim == 2) {
754             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
755               if (vx == numXVertices-1) {
756                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight);CHKERRQ(ierr);
757                 ierr = DMSetLabelValue(dm, "marker", edge,    markerRight);CHKERRQ(ierr);
758                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerRight);CHKERRQ(ierr);
759                 if (ey == numYEdges-1) {
760                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerRight);CHKERRQ(ierr);
761                 }
762               } else if (vx == 0) {
763                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft);CHKERRQ(ierr);
764                 ierr = DMSetLabelValue(dm, "marker", edge,    markerLeft);CHKERRQ(ierr);
765                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerLeft);CHKERRQ(ierr);
766                 if (ey == numYEdges-1) {
767                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerLeft);CHKERRQ(ierr);
768                 }
769               }
770             } else {
771               if (vx == 0 && cutMarker) {
772                 ierr = DMLabelSetValue(cutLabel, edge,    1);CHKERRQ(ierr);
773                 ierr = DMLabelSetValue(cutLabel, cone[0], 1);CHKERRQ(ierr);
774                 if (ey == numYEdges-1) {
775                   ierr = DMLabelSetValue(cutLabel, cone[1], 1);CHKERRQ(ierr);
776                 }
777               }
778             }
779           } else {
780             if (bdX != DM_BOUNDARY_PERIODIC) {
781               if (vx == numXVertices-1) {
782                 ierr = DMSetLabelValue(dm, "marker", edge, markerRight);CHKERRQ(ierr);
783               } else if (vx == 0) {
784                 ierr = DMSetLabelValue(dm, "marker", edge, markerLeft);CHKERRQ(ierr);
785               }
786             }
787             if (bdZ != DM_BOUNDARY_PERIODIC) {
788               if (vz == numZVertices-1) {
789                 ierr = DMSetLabelValue(dm, "marker", edge, markerTop);CHKERRQ(ierr);
790               } else if (vz == 0) {
791                 ierr = DMSetLabelValue(dm, "marker", edge, markerBottom);CHKERRQ(ierr);
792               }
793             }
794           }
795         }
796       }
797     }
798     /* Build X edges*/
799     for (vz = 0; vz < numZVertices; vz++) {
800       for (vy = 0; vy < numYVertices; vy++) {
801         for (ex = 0; ex < numXEdges; ex++) {
802           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges-1) ? (numYVertices-vy-1)*numXVertices : (vz*numYVertices+vy)*numXVertices + (ex+1)%numXVertices;
803           const PetscInt edge    = firstXEdge  + (vz*numYVertices+vy)*numXEdges + ex;
804           const PetscInt vertexL = firstVertex + (vz*numYVertices+vy)*numXVertices + ex;
805           const PetscInt vertexR = firstVertex + nextv;
806           PetscInt       cone[2];
807 
808           cone[0] = vertexL; cone[1] = vertexR;
809           ierr = DMPlexSetCone(dm, edge, cone);CHKERRQ(ierr);
810           if (dim == 2) {
811             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
812               if (vy == numYVertices-1) {
813                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop);CHKERRQ(ierr);
814                 ierr = DMSetLabelValue(dm, "marker", edge,    markerTop);CHKERRQ(ierr);
815                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerTop);CHKERRQ(ierr);
816                 if (ex == numXEdges-1) {
817                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerTop);CHKERRQ(ierr);
818                 }
819               } else if (vy == 0) {
820                 ierr = DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom);CHKERRQ(ierr);
821                 ierr = DMSetLabelValue(dm, "marker", edge,    markerBottom);CHKERRQ(ierr);
822                 ierr = DMSetLabelValue(dm, "marker", cone[0], markerBottom);CHKERRQ(ierr);
823                 if (ex == numXEdges-1) {
824                   ierr = DMSetLabelValue(dm, "marker", cone[1], markerBottom);CHKERRQ(ierr);
825                 }
826               }
827             } else {
828               if (vy == 0 && cutMarker) {
829                 ierr = DMLabelSetValue(cutLabel, edge,    1);CHKERRQ(ierr);
830                 ierr = DMLabelSetValue(cutLabel, cone[0], 1);CHKERRQ(ierr);
831                 if (ex == numXEdges-1) {
832                   ierr = DMLabelSetValue(cutLabel, cone[1], 1);CHKERRQ(ierr);
833                 }
834               }
835             }
836           } else {
837             if (bdY != DM_BOUNDARY_PERIODIC) {
838               if (vy == numYVertices-1) {
839                 ierr = DMSetLabelValue(dm, "marker", edge, markerBack);CHKERRQ(ierr);
840               }
841               else if (vy == 0) {
842                 ierr = DMSetLabelValue(dm, "marker", edge, markerFront);CHKERRQ(ierr);
843               }
844             }
845             if (bdZ != DM_BOUNDARY_PERIODIC) {
846               if (vz == numZVertices-1) {
847                 ierr = DMSetLabelValue(dm, "marker", edge, markerTop);CHKERRQ(ierr);
848               }
849               else if (vz == 0) {
850                 ierr = DMSetLabelValue(dm, "marker", edge, markerBottom);CHKERRQ(ierr);
851               }
852             }
853           }
854         }
855       }
856     }
857     ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
858     ierr = DMPlexStratify(dm);CHKERRQ(ierr);
859     /* Build coordinates */
860     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
861     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
862     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
863     ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numVertices);CHKERRQ(ierr);
864     for (v = firstVertex; v < firstVertex+numVertices; ++v) {
865       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
866       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
867     }
868     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
869     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
870     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
871     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
872     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
873     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
874     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
875     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
876     for (vz = 0; vz < numZVertices; ++vz) {
877       for (vy = 0; vy < numYVertices; ++vy) {
878         for (vx = 0; vx < numXVertices; ++vx) {
879           coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+0] = lower[0] + ((upper[0] - lower[0])/numXEdges)*vx;
880           coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+1] = lower[1] + ((upper[1] - lower[1])/numYEdges)*vy;
881           if (dim == 3) {
882             coords[((vz*numYVertices+vy)*numXVertices+vx)*dim+2] = lower[2] + ((upper[2] - lower[2])/numZEdges)*vz;
883           }
884         }
885       }
886     }
887     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
888     ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
889     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
890   }
891   PetscFunctionReturn(0);
892 }
893 
894 /*@
895   DMPlexCreateHexBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using hexahedra.
896 
897   Collective on MPI_Comm
898 
899   Input Parameters:
900 + comm  - The communicator for the DM object
901 . dim   - The spatial dimension
902 . lower - The lower left corner, or NULL for (0, 0, 0)
903 . upper - The upper right corner, or NULL for (1, 1, 1)
904 . periodicX - The boundary type for the X direction
905 . periodicY - The boundary type for the Y direction
906 . periodicZ - The boundary type for the Z direction
907 - cells - The number of cells in each direction
908 
909   Output Parameter:
910 . dm  - The DM object
911 
912   Note: Here is the numbering returned for 2 cells in each direction:
913 $ 22--8-23--9--24
914 $  |     |     |
915 $ 13  2 14  3  15
916 $  |     |     |
917 $ 19--6-20--7--21
918 $  |     |     |
919 $ 10  0 11  1 12
920 $  |     |     |
921 $ 16--4-17--5--18
922 
923   Level: beginner
924 
925 .keywords: DM, create
926 .seealso: DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
927 @*/
928 PetscErrorCode DMPlexCreateHexBoxMesh(MPI_Comm comm, PetscInt dim, const PetscInt cells[], const PetscReal lower[], const PetscReal upper[], DMBoundaryType periodicX, DMBoundaryType periodicY, DMBoundaryType periodicZ, DM *dm)
929 {
930   PetscInt       i;
931   PetscErrorCode ierr;
932 
933   PetscFunctionBegin;
934   PetscValidPointer(dm, 7);
935   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
936   PetscValidLogicalCollectiveInt(*dm,dim,2);
937   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
938   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
939   switch (dim) {
940   case 2:
941   {
942     PetscReal low[3] = {lower ? lower[0] : 0.0, lower ? lower[1] : 0.0, 0.0};
943     PetscReal upp[3] = {upper ? upper[0] : 1.0, upper ? upper[1] : 1.0, 0.0};
944     PetscInt  edges[3];
945 
946     edges[0] = cells[0];
947     edges[1] = cells[1];
948     edges[2] = 0;
949     ierr = DMPlexCreateCubeMesh_Internal(*dm, low, upp, edges, periodicX, periodicY, DM_BOUNDARY_NONE);CHKERRQ(ierr);
950     if (periodicX == DM_BOUNDARY_PERIODIC || periodicX == DM_BOUNDARY_TWIST ||
951         periodicY == DM_BOUNDARY_PERIODIC || periodicY == DM_BOUNDARY_TWIST) {
952       PetscReal      L[2];
953       PetscReal      maxCell[2];
954       DMBoundaryType bdType[2];
955 
956       bdType[0] = periodicX;
957       bdType[1] = periodicY;
958       for (i = 0; i < dim; i++) {
959         L[i]       = upper[i] - lower[i];
960         maxCell[i] = 1.1 * (L[i] / PetscMax(1,cells[i]));
961       }
962 
963       ierr = DMSetPeriodicity(*dm,PETSC_TRUE,maxCell,L,bdType);CHKERRQ(ierr);
964     }
965     break;
966   }
967   case 3:
968   {
969     PetscReal low[3] = {lower ? lower[0] : 0.0, lower ? lower[1] : 0.0, lower ? lower[2] : 0.0};
970     PetscReal upp[3] = {upper ? upper[0] : 1.0, upper ? upper[1] : 1.0, upper ? upper[2] : 1.0};
971 
972     ierr = DMPlexCreateCubeMesh_Internal(*dm, low, upp, cells, periodicX, periodicY, periodicZ);CHKERRQ(ierr);
973     if (periodicX == DM_BOUNDARY_PERIODIC || periodicX == DM_BOUNDARY_TWIST ||
974         periodicY == DM_BOUNDARY_PERIODIC || periodicY == DM_BOUNDARY_TWIST ||
975         periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
976       PetscReal      L[3];
977       PetscReal      maxCell[3];
978       DMBoundaryType bdType[3];
979 
980       bdType[0] = periodicX;
981       bdType[1] = periodicY;
982       bdType[2] = periodicZ;
983       for (i = 0; i < dim; i++) {
984         L[i]       = upper[i] - lower[i];
985         maxCell[i] = 1.1 * (L[i] / cells[i]);
986       }
987 
988       ierr = DMSetPeriodicity(*dm,PETSC_TRUE,maxCell,L,bdType);CHKERRQ(ierr);
989     }
990     break;
991   }
992   default:
993     SETERRQ1(comm, PETSC_ERR_SUP, "Dimension not supported: %d", dim);
994   }
995   PetscFunctionReturn(0);
996 }
997 
998 /*@C
999   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all DM options in the database.
1000 
1001   Logically Collective on DM
1002 
1003   Input Parameters:
1004 + dm - the DM context
1005 - prefix - the prefix to prepend to all option names
1006 
1007   Notes:
1008   A hyphen (-) must NOT be given at the beginning of the prefix name.
1009   The first character of all runtime options is AUTOMATICALLY the hyphen.
1010 
1011   Level: advanced
1012 
1013 .seealso: SNESSetFromOptions()
1014 @*/
1015 PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
1016 {
1017   DM_Plex       *mesh = (DM_Plex *) dm->data;
1018   PetscErrorCode ierr;
1019 
1020   PetscFunctionBegin;
1021   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1022   ierr = PetscObjectSetOptionsPrefix((PetscObject) dm, prefix);CHKERRQ(ierr);
1023   ierr = PetscObjectSetOptionsPrefix((PetscObject) mesh->partitioner, prefix);CHKERRQ(ierr);
1024   PetscFunctionReturn(0);
1025 }
1026 
1027 /*@
1028   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
1029 
1030   Collective on MPI_Comm
1031 
1032   Input Parameters:
1033 + comm      - The communicator for the DM object
1034 . numRefine - The number of regular refinements to the basic 5 cell structure
1035 - periodicZ - The boundary type for the Z direction
1036 
1037   Output Parameter:
1038 . dm  - The DM object
1039 
1040   Note: Here is the output numbering looking from the bottom of the cylinder:
1041 $       17-----14
1042 $        |     |
1043 $        |  2  |
1044 $        |     |
1045 $ 17-----8-----7-----14
1046 $  |     |     |     |
1047 $  |  3  |  0  |  1  |
1048 $  |     |     |     |
1049 $ 19-----5-----6-----13
1050 $        |     |
1051 $        |  4  |
1052 $        |     |
1053 $       19-----13
1054 $
1055 $ and up through the top
1056 $
1057 $       18-----16
1058 $        |     |
1059 $        |  2  |
1060 $        |     |
1061 $ 18----10----11-----16
1062 $  |     |     |     |
1063 $  |  3  |  0  |  1  |
1064 $  |     |     |     |
1065 $ 20-----9----12-----15
1066 $        |     |
1067 $        |  4  |
1068 $        |     |
1069 $       20-----15
1070 
1071   Level: beginner
1072 
1073 .keywords: DM, create
1074 .seealso: DMPlexCreateHexBoxMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1075 @*/
1076 PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, PetscInt numRefine, DMBoundaryType periodicZ, DM *dm)
1077 {
1078   const PetscInt dim = 3;
1079   PetscInt       numCells, numVertices, r;
1080   PetscErrorCode ierr;
1081 
1082   PetscFunctionBegin;
1083   PetscValidPointer(dm, 4);
1084   if (numRefine < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of refinements %D cannot be negative", numRefine);
1085   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1086   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1087   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1088   /* Create topology */
1089   {
1090     PetscInt cone[8], c;
1091 
1092     numCells    = 5;
1093     numVertices = 16;
1094     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1095       numCells   *= 3;
1096       numVertices = 24;
1097     }
1098     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1099     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 8);CHKERRQ(ierr);}
1100     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1101     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1102       cone[0] = 15; cone[1] = 18; cone[2] = 17; cone[3] = 16;
1103       cone[4] = 31; cone[5] = 32; cone[6] = 33; cone[7] = 34;
1104       ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1105       cone[0] = 16; cone[1] = 17; cone[2] = 24; cone[3] = 23;
1106       cone[4] = 32; cone[5] = 36; cone[6] = 37; cone[7] = 33; /* 22 25 26 21 */
1107       ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1108       cone[0] = 18; cone[1] = 27; cone[2] = 24; cone[3] = 17;
1109       cone[4] = 34; cone[5] = 33; cone[6] = 37; cone[7] = 38;
1110       ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1111       cone[0] = 29; cone[1] = 27; cone[2] = 18; cone[3] = 15;
1112       cone[4] = 35; cone[5] = 31; cone[6] = 34; cone[7] = 38;
1113       ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1114       cone[0] = 29; cone[1] = 15; cone[2] = 16; cone[3] = 23;
1115       cone[4] = 35; cone[5] = 36; cone[6] = 32; cone[7] = 31;
1116       ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1117 
1118       cone[0] = 31; cone[1] = 34; cone[2] = 33; cone[3] = 32;
1119       cone[4] = 19; cone[5] = 22; cone[6] = 21; cone[7] = 20;
1120       ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1121       cone[0] = 32; cone[1] = 33; cone[2] = 37; cone[3] = 36;
1122       cone[4] = 22; cone[5] = 25; cone[6] = 26; cone[7] = 21;
1123       ierr = DMPlexSetCone(*dm, 6, cone);CHKERRQ(ierr);
1124       cone[0] = 34; cone[1] = 38; cone[2] = 37; cone[3] = 33;
1125       cone[4] = 20; cone[5] = 21; cone[6] = 26; cone[7] = 28;
1126       ierr = DMPlexSetCone(*dm, 7, cone);CHKERRQ(ierr);
1127       cone[0] = 35; cone[1] = 38; cone[2] = 34; cone[3] = 31;
1128       cone[4] = 30; cone[5] = 19; cone[6] = 20; cone[7] = 28;
1129       ierr = DMPlexSetCone(*dm, 8, cone);CHKERRQ(ierr);
1130       cone[0] = 35; cone[1] = 31; cone[2] = 32; cone[3] = 36;
1131       cone[4] = 30; cone[5] = 25; cone[6] = 22; cone[7] = 19;
1132       ierr = DMPlexSetCone(*dm, 9, cone);CHKERRQ(ierr);
1133 
1134       cone[0] = 19; cone[1] = 20; cone[2] = 21; cone[3] = 22;
1135       cone[4] = 15; cone[5] = 16; cone[6] = 17; cone[7] = 18;
1136       ierr = DMPlexSetCone(*dm, 10, cone);CHKERRQ(ierr);
1137       cone[0] = 22; cone[1] = 21; cone[2] = 26; cone[3] = 25;
1138       cone[4] = 16; cone[5] = 23; cone[6] = 24; cone[7] = 17;
1139       ierr = DMPlexSetCone(*dm, 11, cone);CHKERRQ(ierr);
1140       cone[0] = 20; cone[1] = 28; cone[2] = 26; cone[3] = 21;
1141       cone[4] = 18; cone[5] = 17; cone[6] = 24; cone[7] = 27;
1142       ierr = DMPlexSetCone(*dm, 12, cone);CHKERRQ(ierr);
1143       cone[0] = 30; cone[1] = 28; cone[2] = 20; cone[3] = 19;
1144       cone[4] = 29; cone[5] = 15; cone[6] = 18; cone[7] = 27;
1145       ierr = DMPlexSetCone(*dm, 13, cone);CHKERRQ(ierr);
1146       cone[0] = 30; cone[1] = 19; cone[2] = 22; cone[3] = 25;
1147       cone[4] = 29; cone[5] = 23; cone[6] = 16; cone[7] = 15;
1148       ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1149     } else {
1150       cone[0] =  5; cone[1] =  8; cone[2] =  7; cone[3] =  6;
1151       cone[4] =  9; cone[5] = 12; cone[6] = 11; cone[7] = 10;
1152       ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1153       cone[0] =  6; cone[1] =  7; cone[2] = 14; cone[3] = 13;
1154       cone[4] = 12; cone[5] = 15; cone[6] = 16; cone[7] = 11;
1155       ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1156       cone[0] =  8; cone[1] = 17; cone[2] = 14; cone[3] =  7;
1157       cone[4] = 10; cone[5] = 11; cone[6] = 16; cone[7] = 18;
1158       ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1159       cone[0] = 19; cone[1] = 17; cone[2] =  8; cone[3] =  5;
1160       cone[4] = 20; cone[5] =  9; cone[6] = 10; cone[7] = 18;
1161       ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1162       cone[0] = 19; cone[1] =  5; cone[2] =  6; cone[3] = 13;
1163       cone[4] = 20; cone[5] = 15; cone[6] = 12; cone[7] =  9;
1164       ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1165     }
1166     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1167     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1168   }
1169   /* Interpolate */
1170   {
1171     DM idm = NULL;
1172 
1173     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1174     ierr = DMDestroy(dm);CHKERRQ(ierr);
1175     *dm  = idm;
1176   }
1177   /* Create cube geometry */
1178   {
1179     Vec             coordinates;
1180     PetscSection    coordSection;
1181     PetscScalar    *coords;
1182     PetscInt        coordSize, v;
1183     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1184     const PetscReal ds2 = dis/2.0;
1185 
1186     /* Build coordinates */
1187     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1188     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1189     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1190     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1191     for (v = numCells; v < numCells+numVertices; ++v) {
1192       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1193       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1194     }
1195     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1196     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1197     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1198     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1199     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1200     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1201     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1202     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1203     coords[0*dim+0] = -ds2; coords[0*dim+1] = -ds2; coords[0*dim+2] = 0.0;
1204     coords[1*dim+0] =  ds2; coords[1*dim+1] = -ds2; coords[1*dim+2] = 0.0;
1205     coords[2*dim+0] =  ds2; coords[2*dim+1] =  ds2; coords[2*dim+2] = 0.0;
1206     coords[3*dim+0] = -ds2; coords[3*dim+1] =  ds2; coords[3*dim+2] = 0.0;
1207     coords[4*dim+0] = -ds2; coords[4*dim+1] = -ds2; coords[4*dim+2] = 1.0;
1208     coords[5*dim+0] = -ds2; coords[5*dim+1] =  ds2; coords[5*dim+2] = 1.0;
1209     coords[6*dim+0] =  ds2; coords[6*dim+1] =  ds2; coords[6*dim+2] = 1.0;
1210     coords[7*dim+0] =  ds2; coords[7*dim+1] = -ds2; coords[7*dim+2] = 1.0;
1211     coords[ 8*dim+0] =  dis; coords[ 8*dim+1] = -dis; coords[ 8*dim+2] = 0.0;
1212     coords[ 9*dim+0] =  dis; coords[ 9*dim+1] =  dis; coords[ 9*dim+2] = 0.0;
1213     coords[10*dim+0] =  dis; coords[10*dim+1] = -dis; coords[10*dim+2] = 1.0;
1214     coords[11*dim+0] =  dis; coords[11*dim+1] =  dis; coords[11*dim+2] = 1.0;
1215     coords[12*dim+0] = -dis; coords[12*dim+1] =  dis; coords[12*dim+2] = 0.0;
1216     coords[13*dim+0] = -dis; coords[13*dim+1] =  dis; coords[13*dim+2] = 1.0;
1217     coords[14*dim+0] = -dis; coords[14*dim+1] = -dis; coords[14*dim+2] = 0.0;
1218     coords[15*dim+0] = -dis; coords[15*dim+1] = -dis; coords[15*dim+2] = 1.0;
1219     if (periodicZ == DM_BOUNDARY_PERIODIC) {
1220       /* 15 31 19 */ coords[16*dim+0] = -ds2; coords[16*dim+1] = -ds2; coords[16*dim+2] = 0.5;
1221       /* 16 32 22 */ coords[17*dim+0] =  ds2; coords[17*dim+1] = -ds2; coords[17*dim+2] = 0.5;
1222       /* 17 33 21 */ coords[18*dim+0] =  ds2; coords[18*dim+1] =  ds2; coords[18*dim+2] = 0.5;
1223       /* 18 34 20 */ coords[19*dim+0] = -ds2; coords[19*dim+1] =  ds2; coords[19*dim+2] = 0.5;
1224       /* 29 35 30 */ coords[20*dim+0] = -dis; coords[20*dim+1] = -dis; coords[20*dim+2] = 0.5;
1225       /* 23 36 25 */ coords[21*dim+0] =  dis; coords[21*dim+1] = -dis; coords[21*dim+2] = 0.5;
1226       /* 24 37 26 */ coords[22*dim+0] =  dis; coords[22*dim+1] =  dis; coords[22*dim+2] = 0.5;
1227       /* 27 38 28 */ coords[23*dim+0] = -dis; coords[23*dim+1] =  dis; coords[23*dim+2] = 0.5;
1228     }
1229     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1230     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1231     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1232   }
1233   /* Create periodicity */
1234   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1235     PetscReal      L[3];
1236     PetscReal      maxCell[3];
1237     DMBoundaryType bdType[3];
1238     PetscReal      lower[3] = {0.0, 0.0, 0.0};
1239     PetscReal      upper[3] = {1.0, 1.0, 1.5};
1240     PetscInt       i, numZCells = 3;
1241 
1242     bdType[0] = DM_BOUNDARY_NONE;
1243     bdType[1] = DM_BOUNDARY_NONE;
1244     bdType[2] = periodicZ;
1245     for (i = 0; i < dim; i++) {
1246       L[i]       = upper[i] - lower[i];
1247       maxCell[i] = 1.1 * (L[i] / numZCells);
1248     }
1249     ierr = DMSetPeriodicity(*dm, PETSC_TRUE, maxCell, L, bdType);CHKERRQ(ierr);
1250   }
1251   /* Refine topology */
1252   for (r = 0; r < numRefine; ++r) {
1253     DM rdm = NULL;
1254 
1255     ierr = DMRefine(*dm, comm, &rdm);CHKERRQ(ierr);
1256     ierr = DMDestroy(dm);CHKERRQ(ierr);
1257     *dm  = rdm;
1258   }
1259   /* Remap geometry to cylinder
1260        Interior square: Linear interpolation is correct
1261        The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
1262        such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
1263 
1264          phi     = arctan(y/x)
1265          d_close = sqrt(1/8 + 1/4 sin^2(phi))
1266          d_far   = sqrt(1/2 + sin^2(phi))
1267 
1268        so we remap them using
1269 
1270          x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
1271          y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
1272 
1273        If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
1274   */
1275   {
1276     Vec           coordinates;
1277     PetscSection  coordSection;
1278     PetscScalar  *coords;
1279     PetscInt      vStart, vEnd, v;
1280     const PetscReal dis = 1.0/PetscSqrtReal(2.0);
1281     const PetscReal ds2 = 0.5*dis;
1282 
1283     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1284     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1285     ierr = DMGetCoordinatesLocal(*dm, &coordinates);CHKERRQ(ierr);
1286     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1287     for (v = vStart; v < vEnd; ++v) {
1288       PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
1289       PetscInt  off;
1290 
1291       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
1292       if ((PetscAbsScalar(coords[off+0]) <= ds2) && (PetscAbsScalar(coords[off+1]) <= ds2)) continue;
1293       x    = PetscRealPart(coords[off]);
1294       y    = PetscRealPart(coords[off+1]);
1295       phi  = PetscAtan2Real(y, x);
1296       sinp = PetscSinReal(phi);
1297       cosp = PetscCosReal(phi);
1298       if ((PetscAbsReal(phi) > PETSC_PI/4.0) && (PetscAbsReal(phi) < 3.0*PETSC_PI/4.0)) {
1299         dc = PetscAbsReal(ds2/sinp);
1300         df = PetscAbsReal(dis/sinp);
1301         xc = ds2*x/PetscAbsReal(y);
1302         yc = ds2*PetscSignReal(y);
1303       } else {
1304         dc = PetscAbsReal(ds2/cosp);
1305         df = PetscAbsReal(dis/cosp);
1306         xc = ds2*PetscSignReal(x);
1307         yc = ds2*y/PetscAbsReal(x);
1308       }
1309       coords[off+0] = xc + (coords[off+0] - xc)*(1.0 - dc)/(df - dc);
1310       coords[off+1] = yc + (coords[off+1] - yc)*(1.0 - dc)/(df - dc);
1311     }
1312     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1313     if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
1314       ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr);
1315     }
1316   }
1317   PetscFunctionReturn(0);
1318 }
1319 
1320 /*@
1321   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
1322 
1323   Collective on MPI_Comm
1324 
1325   Input Parameters:
1326 + comm - The communicator for the DM object
1327 . n    - The number of wedges around the origin
1328 - interpolate - Create edges and faces
1329 
1330   Output Parameter:
1331 . dm  - The DM object
1332 
1333   Level: beginner
1334 
1335 .keywords: DM, create
1336 .seealso: DMPlexCreateHexCylinderMesh(), DMPlexCreateHexBoxMesh(), DMPlexCreateBoxMesh(), DMSetType(), DMCreate()
1337 @*/
1338 PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
1339 {
1340   const PetscInt dim = 3;
1341   PetscInt       numCells, numVertices;
1342   PetscErrorCode ierr;
1343 
1344   PetscFunctionBegin;
1345   PetscValidPointer(dm, 3);
1346   if (n < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %D cannot be negative", n);
1347   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1348   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1349   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1350   /* Create topology */
1351   {
1352     PetscInt cone[6], c;
1353 
1354     numCells    = n;
1355     numVertices = 2*(n+1);
1356     ierr = DMPlexSetChart(*dm, 0, numCells+numVertices);CHKERRQ(ierr);
1357     for (c = 0; c < numCells; c++) {ierr = DMPlexSetConeSize(*dm, c, 6);CHKERRQ(ierr);}
1358     ierr = DMSetUp(*dm);CHKERRQ(ierr);
1359     for (c = 0; c < numCells; c++) {
1360       cone[0] =  c+n*1; cone[1] = (c+1)%n+n*1; cone[2] = 0+3*n;
1361       cone[3] =  c+n*2; cone[4] = (c+1)%n+n*2; cone[5] = 1+3*n;
1362       ierr = DMPlexSetCone(*dm, c, cone);CHKERRQ(ierr);
1363     }
1364     ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1365     ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1366   }
1367   /* Interpolate */
1368   if (interpolate) {
1369     DM idm = NULL;
1370 
1371     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1372     ierr = DMDestroy(dm);CHKERRQ(ierr);
1373     *dm  = idm;
1374   }
1375   /* Create cylinder geometry */
1376   {
1377     Vec          coordinates;
1378     PetscSection coordSection;
1379     PetscScalar *coords;
1380     PetscInt     coordSize, v, c;
1381 
1382     /* Build coordinates */
1383     ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1384     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1385     ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
1386     ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVertices);CHKERRQ(ierr);
1387     for (v = numCells; v < numCells+numVertices; ++v) {
1388       ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
1389       ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
1390     }
1391     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1392     ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1393     ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1394     ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1395     ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1396     ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
1397     ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1398     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1399     for (c = 0; c < numCells; c++) {
1400       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;
1401       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;
1402     }
1403     coords[(2*n+0)*dim+0] = 0.0; coords[(2*n+0)*dim+1] = 0.0; coords[(2*n+0)*dim+2] = 1.0;
1404     coords[(2*n+1)*dim+0] = 0.0; coords[(2*n+1)*dim+1] = 0.0; coords[(2*n+1)*dim+2] = 0.0;
1405     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1406     ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1407     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1408   }
1409   PetscFunctionReturn(0);
1410 }
1411 
1412 PETSC_STATIC_INLINE PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1413 {
1414   PetscReal prod = 0.0;
1415   PetscInt  i;
1416   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
1417   return PetscSqrtReal(prod);
1418 }
1419 PETSC_STATIC_INLINE PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
1420 {
1421   PetscReal prod = 0.0;
1422   PetscInt  i;
1423   for (i = 0; i < dim; ++i) prod += x[i]*y[i];
1424   return prod;
1425 }
1426 
1427 /*@
1428   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
1429 
1430   Collective on MPI_Comm
1431 
1432   Input Parameters:
1433 . comm  - The communicator for the DM object
1434 . dim   - The dimension
1435 - simplex - Use simplices, or tensor product cells
1436 
1437   Output Parameter:
1438 . dm  - The DM object
1439 
1440   Level: beginner
1441 
1442 .keywords: DM, create
1443 .seealso: DMPlexCreateBoxMesh(), DMPlexCreateHexBoxMesh(), DMSetType(), DMCreate()
1444 @*/
1445 PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *dm)
1446 {
1447   const PetscInt  embedDim = dim+1;
1448   PetscSection    coordSection;
1449   Vec             coordinates;
1450   PetscScalar    *coords;
1451   PetscReal      *coordsIn;
1452   PetscInt        numCells, numEdges, numVerts, firstVertex, v, firstEdge, coordSize, d, c, e;
1453   PetscMPIInt     rank;
1454   PetscErrorCode  ierr;
1455 
1456   PetscFunctionBegin;
1457   PetscValidPointer(dm, 4);
1458   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1459   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1460   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1461   ierr = DMSetCoordinateDim(*dm, dim+1);CHKERRQ(ierr);
1462   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) *dm), &rank);CHKERRQ(ierr);
1463   switch (dim) {
1464   case 2:
1465     if (simplex) {
1466       DM              idm         = NULL;
1467       const PetscReal edgeLen     = 2.0/(1.0 + PETSC_PHI);
1468       const PetscReal vertex[3]   = {0.0, 1.0/(1.0 + PETSC_PHI), PETSC_PHI/(1.0 + PETSC_PHI)};
1469       const PetscInt  degree      = 5;
1470       PetscInt        s[3]        = {1, 1, 1};
1471       PetscInt        cone[3];
1472       PetscInt       *graph, p, i, j, k;
1473 
1474       numCells    = !rank ? 20 : 0;
1475       numVerts    = !rank ? 12 : 0;
1476       firstVertex = numCells;
1477       /* Use icosahedron, which for a unit sphere has coordinates which are all cyclic permutations of
1478 
1479            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
1480 
1481          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
1482          length is then given by 2/\phi = 2 * 2.73606 = 5.47214.
1483        */
1484       /* Construct vertices */
1485       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1486       for (p = 0, i = 0; p < embedDim; ++p) {
1487         for (s[1] = -1; s[1] < 2; s[1] += 2) {
1488           for (s[2] = -1; s[2] < 2; s[2] += 2) {
1489             for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertex[(d+p)%embedDim];
1490             ++i;
1491           }
1492         }
1493       }
1494       /* Construct graph */
1495       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
1496       for (i = 0; i < numVerts; ++i) {
1497         for (j = 0, k = 0; j < numVerts; ++j) {
1498           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
1499         }
1500         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid icosahedron, vertex %D degree %D != %D", i, k, degree);
1501       }
1502       /* Build Topology */
1503       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
1504       for (c = 0; c < numCells; c++) {
1505         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
1506       }
1507       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1508       /* Cells */
1509       for (i = 0, c = 0; i < numVerts; ++i) {
1510         for (j = 0; j < i; ++j) {
1511           for (k = 0; k < j; ++k) {
1512             if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i]) {
1513               cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k;
1514               /* Check orientation */
1515               {
1516                 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}}};
1517                 PetscReal normal[3];
1518                 PetscInt  e, f;
1519 
1520                 for (d = 0; d < embedDim; ++d) {
1521                   normal[d] = 0.0;
1522                   for (e = 0; e < embedDim; ++e) {
1523                     for (f = 0; f < embedDim; ++f) {
1524                       normal[d] += epsilon[d][e][f]*(coordsIn[j*embedDim+e] - coordsIn[i*embedDim+e])*(coordsIn[k*embedDim+f] - coordsIn[i*embedDim+f]);
1525                     }
1526                   }
1527                 }
1528                 if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
1529               }
1530               ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
1531             }
1532           }
1533         }
1534       }
1535       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1536       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1537       ierr = PetscFree(graph);CHKERRQ(ierr);
1538       /* Interpolate mesh */
1539       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1540       ierr = DMDestroy(dm);CHKERRQ(ierr);
1541       *dm  = idm;
1542     } else {
1543       /*
1544         12-21--13
1545          |     |
1546         25  4  24
1547          |     |
1548   12-25--9-16--8-24--13
1549    |     |     |     |
1550   23  5 17  0 15  3  22
1551    |     |     |     |
1552   10-20--6-14--7-19--11
1553          |     |
1554         20  1  19
1555          |     |
1556         10-18--11
1557          |     |
1558         23  2  22
1559          |     |
1560         12-21--13
1561        */
1562       const PetscReal dist = 1.0/PetscSqrtReal(3.0);
1563       PetscInt        cone[4], ornt[4];
1564 
1565       numCells    = !rank ?  6 : 0;
1566       numEdges    = !rank ? 12 : 0;
1567       numVerts    = !rank ?  8 : 0;
1568       firstVertex = numCells;
1569       firstEdge   = numCells + numVerts;
1570       /* Build Topology */
1571       ierr = DMPlexSetChart(*dm, 0, numCells+numEdges+numVerts);CHKERRQ(ierr);
1572       for (c = 0; c < numCells; c++) {
1573         ierr = DMPlexSetConeSize(*dm, c, 4);CHKERRQ(ierr);
1574       }
1575       for (e = firstEdge; e < firstEdge+numEdges; ++e) {
1576         ierr = DMPlexSetConeSize(*dm, e, 2);CHKERRQ(ierr);
1577       }
1578       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1579       /* Cell 0 */
1580       cone[0] = 14; cone[1] = 15; cone[2] = 16; cone[3] = 17;
1581       ierr = DMPlexSetCone(*dm, 0, cone);CHKERRQ(ierr);
1582       ornt[0] = 0; ornt[1] = 0; ornt[2] = 0; ornt[3] = 0;
1583       ierr = DMPlexSetConeOrientation(*dm, 0, ornt);CHKERRQ(ierr);
1584       /* Cell 1 */
1585       cone[0] = 18; cone[1] = 19; cone[2] = 14; cone[3] = 20;
1586       ierr = DMPlexSetCone(*dm, 1, cone);CHKERRQ(ierr);
1587       ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1588       ierr = DMPlexSetConeOrientation(*dm, 1, ornt);CHKERRQ(ierr);
1589       /* Cell 2 */
1590       cone[0] = 21; cone[1] = 22; cone[2] = 18; cone[3] = 23;
1591       ierr = DMPlexSetCone(*dm, 2, cone);CHKERRQ(ierr);
1592       ornt[0] = 0; ornt[1] = 0; ornt[2] = -2; ornt[3] = 0;
1593       ierr = DMPlexSetConeOrientation(*dm, 2, ornt);CHKERRQ(ierr);
1594       /* Cell 3 */
1595       cone[0] = 19; cone[1] = 22; cone[2] = 24; cone[3] = 15;
1596       ierr = DMPlexSetCone(*dm, 3, cone);CHKERRQ(ierr);
1597       ornt[0] = -2; ornt[1] = -2; ornt[2] = 0; ornt[3] = -2;
1598       ierr = DMPlexSetConeOrientation(*dm, 3, ornt);CHKERRQ(ierr);
1599       /* Cell 4 */
1600       cone[0] = 16; cone[1] = 24; cone[2] = 21; cone[3] = 25;
1601       ierr = DMPlexSetCone(*dm, 4, cone);CHKERRQ(ierr);
1602       ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = 0;
1603       ierr = DMPlexSetConeOrientation(*dm, 4, ornt);CHKERRQ(ierr);
1604       /* Cell 5 */
1605       cone[0] = 20; cone[1] = 17; cone[2] = 25; cone[3] = 23;
1606       ierr = DMPlexSetCone(*dm, 5, cone);CHKERRQ(ierr);
1607       ornt[0] = -2; ornt[1] = -2; ornt[2] = -2; ornt[3] = -2;
1608       ierr = DMPlexSetConeOrientation(*dm, 5, ornt);CHKERRQ(ierr);
1609       /* Edges */
1610       cone[0] =  6; cone[1] =  7;
1611       ierr = DMPlexSetCone(*dm, 14, cone);CHKERRQ(ierr);
1612       cone[0] =  7; cone[1] =  8;
1613       ierr = DMPlexSetCone(*dm, 15, cone);CHKERRQ(ierr);
1614       cone[0] =  8; cone[1] =  9;
1615       ierr = DMPlexSetCone(*dm, 16, cone);CHKERRQ(ierr);
1616       cone[0] =  9; cone[1] =  6;
1617       ierr = DMPlexSetCone(*dm, 17, cone);CHKERRQ(ierr);
1618       cone[0] = 10; cone[1] = 11;
1619       ierr = DMPlexSetCone(*dm, 18, cone);CHKERRQ(ierr);
1620       cone[0] = 11; cone[1] =  7;
1621       ierr = DMPlexSetCone(*dm, 19, cone);CHKERRQ(ierr);
1622       cone[0] =  6; cone[1] = 10;
1623       ierr = DMPlexSetCone(*dm, 20, cone);CHKERRQ(ierr);
1624       cone[0] = 12; cone[1] = 13;
1625       ierr = DMPlexSetCone(*dm, 21, cone);CHKERRQ(ierr);
1626       cone[0] = 13; cone[1] = 11;
1627       ierr = DMPlexSetCone(*dm, 22, cone);CHKERRQ(ierr);
1628       cone[0] = 10; cone[1] = 12;
1629       ierr = DMPlexSetCone(*dm, 23, cone);CHKERRQ(ierr);
1630       cone[0] = 13; cone[1] =  8;
1631       ierr = DMPlexSetCone(*dm, 24, cone);CHKERRQ(ierr);
1632       cone[0] = 12; cone[1] =  9;
1633       ierr = DMPlexSetCone(*dm, 25, cone);CHKERRQ(ierr);
1634       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1635       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1636       /* Build coordinates */
1637       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1638       coordsIn[0*embedDim+0] = -dist; coordsIn[0*embedDim+1] =  dist; coordsIn[0*embedDim+2] = -dist;
1639       coordsIn[1*embedDim+0] =  dist; coordsIn[1*embedDim+1] =  dist; coordsIn[1*embedDim+2] = -dist;
1640       coordsIn[2*embedDim+0] =  dist; coordsIn[2*embedDim+1] = -dist; coordsIn[2*embedDim+2] = -dist;
1641       coordsIn[3*embedDim+0] = -dist; coordsIn[3*embedDim+1] = -dist; coordsIn[3*embedDim+2] = -dist;
1642       coordsIn[4*embedDim+0] = -dist; coordsIn[4*embedDim+1] =  dist; coordsIn[4*embedDim+2] =  dist;
1643       coordsIn[5*embedDim+0] =  dist; coordsIn[5*embedDim+1] =  dist; coordsIn[5*embedDim+2] =  dist;
1644       coordsIn[6*embedDim+0] = -dist; coordsIn[6*embedDim+1] = -dist; coordsIn[6*embedDim+2] =  dist;
1645       coordsIn[7*embedDim+0] =  dist; coordsIn[7*embedDim+1] = -dist; coordsIn[7*embedDim+2] =  dist;
1646     }
1647     break;
1648   case 3:
1649     if (simplex) {
1650       DM              idm             = NULL;
1651       const PetscReal edgeLen         = 1.0/PETSC_PHI;
1652       const PetscReal vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
1653       const PetscReal vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
1654       const PetscReal vertexC[4]      = {0.5, 0.5*PETSC_PHI, 0.5/PETSC_PHI, 0.0};
1655       const PetscInt  degree          = 12;
1656       PetscInt        s[4]            = {1, 1, 1};
1657       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},
1658                                          {2, 0, 1, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 2, 1, 0}};
1659       PetscInt        cone[4];
1660       PetscInt       *graph, p, i, j, k, l;
1661 
1662       numCells    = !rank ? 600 : 0;
1663       numVerts    = !rank ? 120 : 0;
1664       firstVertex = numCells;
1665       /* Use the 600-cell, which for a unit sphere has coordinates which are
1666 
1667            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
1668                (\pm 1,    0,       0,      0)  all cyclic permutations   8
1669            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
1670 
1671          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
1672          length is then given by 1/\phi = 2.73606.
1673 
1674          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
1675          http://mathworld.wolfram.com/600-Cell.html
1676        */
1677       /* Construct vertices */
1678       ierr = PetscCalloc1(numVerts * embedDim, &coordsIn);CHKERRQ(ierr);
1679       i    = 0;
1680       for (s[0] = -1; s[0] < 2; s[0] += 2) {
1681         for (s[1] = -1; s[1] < 2; s[1] += 2) {
1682           for (s[2] = -1; s[2] < 2; s[2] += 2) {
1683             for (s[3] = -1; s[3] < 2; s[3] += 2) {
1684               for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[d]*vertexA[d];
1685               ++i;
1686             }
1687           }
1688         }
1689       }
1690       for (p = 0; p < embedDim; ++p) {
1691         s[1] = s[2] = s[3] = 1;
1692         for (s[0] = -1; s[0] < 2; s[0] += 2) {
1693           for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[(d+p)%embedDim]*vertexB[(d+p)%embedDim];
1694           ++i;
1695         }
1696       }
1697       for (p = 0; p < 12; ++p) {
1698         s[3] = 1;
1699         for (s[0] = -1; s[0] < 2; s[0] += 2) {
1700           for (s[1] = -1; s[1] < 2; s[1] += 2) {
1701             for (s[2] = -1; s[2] < 2; s[2] += 2) {
1702               for (d = 0; d < embedDim; ++d) coordsIn[i*embedDim+d] = s[evenPerm[p][d]]*vertexC[evenPerm[p][d]];
1703               ++i;
1704             }
1705           }
1706         }
1707       }
1708       if (i != numVerts) SETERRQ2(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertices %D != %D", i, numVerts);
1709       /* Construct graph */
1710       ierr = PetscCalloc1(numVerts * numVerts, &graph);CHKERRQ(ierr);
1711       for (i = 0; i < numVerts; ++i) {
1712         for (j = 0, k = 0; j < numVerts; ++j) {
1713           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i*embedDim], &coordsIn[j*embedDim]) - edgeLen) < PETSC_SMALL) {graph[i*numVerts+j] = 1; ++k;}
1714         }
1715         if (k != degree) SETERRQ3(comm, PETSC_ERR_PLIB, "Invalid 600-cell, vertex %D degree %D != %D", i, k, degree);
1716       }
1717       /* Build Topology */
1718       ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
1719       for (c = 0; c < numCells; c++) {
1720         ierr = DMPlexSetConeSize(*dm, c, embedDim);CHKERRQ(ierr);
1721       }
1722       ierr = DMSetUp(*dm);CHKERRQ(ierr); /* Allocate space for cones */
1723       /* Cells */
1724       for (i = 0, c = 0; i < numVerts; ++i) {
1725         for (j = 0; j < i; ++j) {
1726           for (k = 0; k < j; ++k) {
1727             for (l = 0; l < k; ++l) {
1728               if (graph[i*numVerts+j] && graph[j*numVerts+k] && graph[k*numVerts+i] &&
1729                   graph[l*numVerts+i] && graph[l*numVerts+j] && graph[l*numVerts+k]) {
1730                 cone[0] = firstVertex+i; cone[1] = firstVertex+j; cone[2] = firstVertex+k; cone[3] = firstVertex+l;
1731                 /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
1732                 {
1733                   const PetscInt epsilon[4][4][4][4] = {{{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
1734                                                          {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  1}, { 0,  0, -1, 0}},
1735                                                          {{0,  0,  0,  0}, { 0, 0,  0, -1}, { 0,  0, 0,  0}, { 0,  1,  0, 0}},
1736                                                          {{0,  0,  0,  0}, { 0, 0,  1,  0}, { 0, -1, 0,  0}, { 0,  0,  0, 0}}},
1737 
1738                                                         {{{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0, -1}, { 0,  0,  1, 0}},
1739                                                          {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
1740                                                          {{0,  0,  0,  1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, {-1,  0,  0, 0}},
1741                                                          {{0,  0, -1,  0}, { 0, 0,  0,  0}, { 1,  0, 0,  0}, { 0,  0,  0, 0}}},
1742 
1743                                                         {{{0,  0,  0,  0}, { 0, 0,  0,  1}, { 0,  0, 0,  0}, { 0, -1,  0, 0}},
1744                                                          {{0,  0,  0, -1}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 1,  0,  0, 0}},
1745                                                          {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
1746                                                          {{0,  1,  0,  0}, {-1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}},
1747 
1748                                                         {{{0,  0,  0,  0}, { 0, 0, -1,  0}, { 0,  1, 0,  0}, { 0,  0,  0, 0}},
1749                                                          {{0,  0,  1,  0}, { 0, 0,  0,  0}, {-1,  0, 0,  0}, { 0,  0,  0, 0}},
1750                                                          {{0, -1,  0,  0}, { 1, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}},
1751                                                          {{0,  0,  0,  0}, { 0, 0,  0,  0}, { 0,  0, 0,  0}, { 0,  0,  0, 0}}}};
1752                   PetscReal normal[4];
1753                   PetscInt  e, f, g;
1754 
1755                   for (d = 0; d < embedDim; ++d) {
1756                     normal[d] = 0.0;
1757                     for (e = 0; e < embedDim; ++e) {
1758                       for (f = 0; f < embedDim; ++f) {
1759                         for (g = 0; g < embedDim; ++g) {
1760                           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]);
1761                         }
1762                       }
1763                     }
1764                   }
1765                   if (DotReal(embedDim, normal, &coordsIn[i*embedDim]) < 0) {PetscInt tmp = cone[1]; cone[1] = cone[2]; cone[2] = tmp;}
1766                 }
1767                 ierr = DMPlexSetCone(*dm, c++, cone);CHKERRQ(ierr);
1768               }
1769             }
1770           }
1771         }
1772       }
1773       ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1774       ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1775       ierr = PetscFree(graph);CHKERRQ(ierr);
1776       /* Interpolate mesh */
1777       ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1778       ierr = DMDestroy(dm);CHKERRQ(ierr);
1779       *dm  = idm;
1780       break;
1781     }
1782   default: SETERRQ1(comm, PETSC_ERR_SUP, "Unsupported dimension for sphere: %D", dim);
1783   }
1784   /* Create coordinates */
1785   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
1786   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1787   ierr = PetscSectionSetFieldComponents(coordSection, 0, embedDim);CHKERRQ(ierr);
1788   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numVerts);CHKERRQ(ierr);
1789   for (v = firstVertex; v < firstVertex+numVerts; ++v) {
1790     ierr = PetscSectionSetDof(coordSection, v, embedDim);CHKERRQ(ierr);
1791     ierr = PetscSectionSetFieldDof(coordSection, v, 0, embedDim);CHKERRQ(ierr);
1792   }
1793   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
1795   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
1796   ierr = VecSetBlockSize(coordinates, embedDim);CHKERRQ(ierr);
1797   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1798   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
1799   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
1800   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1801   for (v = 0; v < numVerts; ++v) for (d = 0; d < embedDim; ++d) {coords[v*embedDim+d] = coordsIn[v*embedDim+d];}
1802   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1803   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1804   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1805   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
1806   PetscFunctionReturn(0);
1807 }
1808 
1809 /* External function declarations here */
1810 extern PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling);
1811 extern PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat);
1812 extern PetscErrorCode DMCreateDefaultSection_Plex(DM dm);
1813 extern PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm);
1814 extern PetscErrorCode DMCreateMatrix_Plex(DM dm,  Mat *J);
1815 extern PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm);
1816 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm);
1817 extern PetscErrorCode DMSetUp_Plex(DM dm);
1818 extern PetscErrorCode DMDestroy_Plex(DM dm);
1819 extern PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer);
1820 extern PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer);
1821 extern PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm);
1822 static PetscErrorCode DMInitialize_Plex(DM dm);
1823 
1824 /* Replace dm with the contents of dmNew
1825    - Share the DM_Plex structure
1826    - Share the coordinates
1827    - Share the SF
1828 */
1829 static PetscErrorCode DMPlexReplace_Static(DM dm, DM dmNew)
1830 {
1831   PetscSF               sf;
1832   DM                    coordDM, coarseDM;
1833   Vec                   coords;
1834   PetscBool             isper;
1835   const PetscReal      *maxCell, *L;
1836   const DMBoundaryType *bd;
1837   PetscErrorCode        ierr;
1838 
1839   PetscFunctionBegin;
1840   ierr = DMGetPointSF(dmNew, &sf);CHKERRQ(ierr);
1841   ierr = DMSetPointSF(dm, sf);CHKERRQ(ierr);
1842   ierr = DMGetCoordinateDM(dmNew, &coordDM);CHKERRQ(ierr);
1843   ierr = DMGetCoordinatesLocal(dmNew, &coords);CHKERRQ(ierr);
1844   ierr = DMSetCoordinateDM(dm, coordDM);CHKERRQ(ierr);
1845   ierr = DMSetCoordinatesLocal(dm, coords);CHKERRQ(ierr);
1846   ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
1847   ierr = DMSetPeriodicity(dmNew, isper, maxCell, L, bd);CHKERRQ(ierr);
1848   ierr = DMDestroy_Plex(dm);CHKERRQ(ierr);
1849   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
1850   dm->data = dmNew->data;
1851   ((DM_Plex *) dmNew->data)->refct++;
1852   dmNew->labels->refct++;
1853   if (!--(dm->labels->refct)) {
1854     DMLabelLink next = dm->labels->next;
1855 
1856     /* destroy the labels */
1857     while (next) {
1858       DMLabelLink tmp = next->next;
1859 
1860       ierr = DMLabelDestroy(&next->label);CHKERRQ(ierr);
1861       ierr = PetscFree(next);CHKERRQ(ierr);
1862       next = tmp;
1863     }
1864     ierr = PetscFree(dm->labels);CHKERRQ(ierr);
1865   }
1866   dm->labels = dmNew->labels;
1867   dm->depthLabel = dmNew->depthLabel;
1868   ierr = DMGetCoarseDM(dmNew,&coarseDM);CHKERRQ(ierr);
1869   ierr = DMSetCoarseDM(dm,coarseDM);CHKERRQ(ierr);
1870   PetscFunctionReturn(0);
1871 }
1872 
1873 /* Swap dm with the contents of dmNew
1874    - Swap the DM_Plex structure
1875    - Swap the coordinates
1876    - Swap the point PetscSF
1877 */
1878 static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
1879 {
1880   DM              coordDMA, coordDMB;
1881   Vec             coordsA,  coordsB;
1882   PetscSF         sfA,      sfB;
1883   void            *tmp;
1884   DMLabelLinkList listTmp;
1885   DMLabel         depthTmp;
1886   PetscErrorCode  ierr;
1887 
1888   PetscFunctionBegin;
1889   ierr = DMGetPointSF(dmA, &sfA);CHKERRQ(ierr);
1890   ierr = DMGetPointSF(dmB, &sfB);CHKERRQ(ierr);
1891   ierr = PetscObjectReference((PetscObject) sfA);CHKERRQ(ierr);
1892   ierr = DMSetPointSF(dmA, sfB);CHKERRQ(ierr);
1893   ierr = DMSetPointSF(dmB, sfA);CHKERRQ(ierr);
1894   ierr = PetscObjectDereference((PetscObject) sfA);CHKERRQ(ierr);
1895 
1896   ierr = DMGetCoordinateDM(dmA, &coordDMA);CHKERRQ(ierr);
1897   ierr = DMGetCoordinateDM(dmB, &coordDMB);CHKERRQ(ierr);
1898   ierr = PetscObjectReference((PetscObject) coordDMA);CHKERRQ(ierr);
1899   ierr = DMSetCoordinateDM(dmA, coordDMB);CHKERRQ(ierr);
1900   ierr = DMSetCoordinateDM(dmB, coordDMA);CHKERRQ(ierr);
1901   ierr = PetscObjectDereference((PetscObject) coordDMA);CHKERRQ(ierr);
1902 
1903   ierr = DMGetCoordinatesLocal(dmA, &coordsA);CHKERRQ(ierr);
1904   ierr = DMGetCoordinatesLocal(dmB, &coordsB);CHKERRQ(ierr);
1905   ierr = PetscObjectReference((PetscObject) coordsA);CHKERRQ(ierr);
1906   ierr = DMSetCoordinatesLocal(dmA, coordsB);CHKERRQ(ierr);
1907   ierr = DMSetCoordinatesLocal(dmB, coordsA);CHKERRQ(ierr);
1908   ierr = PetscObjectDereference((PetscObject) coordsA);CHKERRQ(ierr);
1909 
1910   tmp       = dmA->data;
1911   dmA->data = dmB->data;
1912   dmB->data = tmp;
1913   listTmp   = dmA->labels;
1914   dmA->labels = dmB->labels;
1915   dmB->labels = listTmp;
1916   depthTmp  = dmA->depthLabel;
1917   dmA->depthLabel = dmB->depthLabel;
1918   dmB->depthLabel = depthTmp;
1919   PetscFunctionReturn(0);
1920 }
1921 
1922 PetscErrorCode DMSetFromOptions_NonRefinement_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
1923 {
1924   DM_Plex       *mesh = (DM_Plex*) dm->data;
1925   PetscErrorCode ierr;
1926 
1927   PetscFunctionBegin;
1928   /* Handle viewing */
1929   ierr = PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMView", PETSC_FALSE, &mesh->printSetValues, NULL);CHKERRQ(ierr);
1930   ierr = PetscOptionsInt("-dm_plex_print_fem", "Debug output level all fem computations", "DMView", 0, &mesh->printFEM, NULL);CHKERRQ(ierr);
1931   ierr = PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMView", mesh->printTol, &mesh->printTol, NULL);CHKERRQ(ierr);
1932   /* Point Location */
1933   ierr = PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMView", PETSC_FALSE, &mesh->useHashLocation, NULL);CHKERRQ(ierr);
1934   /* Generation and remeshing */
1935   ierr = PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMView", PETSC_FALSE, &mesh->remeshBd, NULL);CHKERRQ(ierr);
1936   /* Projection behavior */
1937   ierr = PetscOptionsInt("-dm_plex_max_projection_height", "Maxmimum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL);CHKERRQ(ierr);
1938   ierr = PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL);CHKERRQ(ierr);
1939 
1940   ierr = PetscPartitionerSetFromOptions(mesh->partitioner);CHKERRQ(ierr);
1941   PetscFunctionReturn(0);
1942 }
1943 
1944 static PetscErrorCode DMSetFromOptions_Plex(PetscOptionItems *PetscOptionsObject,DM dm)
1945 {
1946   PetscInt       refine = 0, coarsen = 0, r;
1947   PetscBool      isHierarchy;
1948   PetscErrorCode ierr;
1949 
1950   PetscFunctionBegin;
1951   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1952   ierr = PetscOptionsHead(PetscOptionsObject,"DMPlex Options");CHKERRQ(ierr);
1953   /* Handle DMPlex refinement */
1954   ierr = PetscOptionsInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL);CHKERRQ(ierr);
1955   ierr = PetscOptionsInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy);CHKERRQ(ierr);
1956   if (refine) {ierr = DMPlexSetRefinementUniform(dm, PETSC_TRUE);CHKERRQ(ierr);}
1957   if (refine && isHierarchy) {
1958     DM *dms, coarseDM;
1959 
1960     ierr = DMGetCoarseDM(dm, &coarseDM);CHKERRQ(ierr);
1961     ierr = PetscObjectReference((PetscObject)coarseDM);CHKERRQ(ierr);
1962     ierr = PetscMalloc1(refine,&dms);CHKERRQ(ierr);
1963     ierr = DMRefineHierarchy(dm, refine, dms);CHKERRQ(ierr);
1964     /* Total hack since we do not pass in a pointer */
1965     ierr = DMPlexSwap_Static(dm, dms[refine-1]);CHKERRQ(ierr);
1966     if (refine == 1) {
1967       ierr = DMSetCoarseDM(dm, dms[0]);CHKERRQ(ierr);
1968       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
1969     } else {
1970       ierr = DMSetCoarseDM(dm, dms[refine-2]);CHKERRQ(ierr);
1971       ierr = DMPlexSetRegularRefinement(dm, PETSC_TRUE);CHKERRQ(ierr);
1972       ierr = DMSetCoarseDM(dms[0], dms[refine-1]);CHKERRQ(ierr);
1973       ierr = DMPlexSetRegularRefinement(dms[0], PETSC_TRUE);CHKERRQ(ierr);
1974     }
1975     ierr = DMSetCoarseDM(dms[refine-1], coarseDM);CHKERRQ(ierr);
1976     ierr = PetscObjectDereference((PetscObject)coarseDM);CHKERRQ(ierr);
1977     /* Free DMs */
1978     for (r = 0; r < refine; ++r) {
1979       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
1980       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
1981     }
1982     ierr = PetscFree(dms);CHKERRQ(ierr);
1983   } else {
1984     for (r = 0; r < refine; ++r) {
1985       DM refinedMesh;
1986 
1987       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
1988       ierr = DMRefine(dm, PetscObjectComm((PetscObject) dm), &refinedMesh);CHKERRQ(ierr);
1989       /* Total hack since we do not pass in a pointer */
1990       ierr = DMPlexReplace_Static(dm, refinedMesh);CHKERRQ(ierr);
1991       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
1992       ierr = DMDestroy(&refinedMesh);CHKERRQ(ierr);
1993     }
1994   }
1995   /* Handle DMPlex coarsening */
1996   ierr = PetscOptionsInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL);CHKERRQ(ierr);
1997   ierr = PetscOptionsInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy);CHKERRQ(ierr);
1998   if (coarsen && isHierarchy) {
1999     DM *dms;
2000 
2001     ierr = PetscMalloc1(coarsen, &dms);CHKERRQ(ierr);
2002     ierr = DMCoarsenHierarchy(dm, coarsen, dms);CHKERRQ(ierr);
2003     /* Free DMs */
2004     for (r = 0; r < coarsen; ++r) {
2005       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dms[r]);CHKERRQ(ierr);
2006       ierr = DMDestroy(&dms[r]);CHKERRQ(ierr);
2007     }
2008     ierr = PetscFree(dms);CHKERRQ(ierr);
2009   } else {
2010     for (r = 0; r < coarsen; ++r) {
2011       DM coarseMesh;
2012 
2013       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2014       ierr = DMCoarsen(dm, PetscObjectComm((PetscObject) dm), &coarseMesh);CHKERRQ(ierr);
2015       /* Total hack since we do not pass in a pointer */
2016       ierr = DMPlexReplace_Static(dm, coarseMesh);CHKERRQ(ierr);
2017       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2018       ierr = DMDestroy(&coarseMesh);CHKERRQ(ierr);
2019     }
2020   }
2021   /* Handle */
2022   ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject, dm);CHKERRQ(ierr);
2023   ierr = PetscOptionsTail();CHKERRQ(ierr);
2024   PetscFunctionReturn(0);
2025 }
2026 
2027 static PetscErrorCode DMCreateGlobalVector_Plex(DM dm,Vec *vec)
2028 {
2029   PetscErrorCode ierr;
2030 
2031   PetscFunctionBegin;
2032   ierr = DMCreateGlobalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2033   /* ierr = VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM);CHKERRQ(ierr); */
2034   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex);CHKERRQ(ierr);
2035   ierr = VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void)) VecView_Plex_Native);CHKERRQ(ierr);
2036   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex);CHKERRQ(ierr);
2037   ierr = VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void)) VecLoad_Plex_Native);CHKERRQ(ierr);
2038   PetscFunctionReturn(0);
2039 }
2040 
2041 static PetscErrorCode DMCreateLocalVector_Plex(DM dm,Vec *vec)
2042 {
2043   PetscErrorCode ierr;
2044 
2045   PetscFunctionBegin;
2046   ierr = DMCreateLocalVector_Section_Private(dm,vec);CHKERRQ(ierr);
2047   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void)) VecView_Plex_Local);CHKERRQ(ierr);
2048   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void)) VecLoad_Plex_Local);CHKERRQ(ierr);
2049   PetscFunctionReturn(0);
2050 }
2051 
2052 static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
2053 {
2054   PetscInt       depth, d;
2055   PetscErrorCode ierr;
2056 
2057   PetscFunctionBegin;
2058   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2059   if (depth == 1) {
2060     ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
2061     if (dim == 0)      {ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);}
2062     else if (dim == d) {ierr = DMPlexGetDepthStratum(dm, 1, pStart, pEnd);CHKERRQ(ierr);}
2063     else               {*pStart = 0; *pEnd = 0;}
2064   } else {
2065     ierr = DMPlexGetDepthStratum(dm, dim, pStart, pEnd);CHKERRQ(ierr);
2066   }
2067   PetscFunctionReturn(0);
2068 }
2069 
2070 static PetscErrorCode DMGetNeighors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
2071 {
2072   PetscSF        sf;
2073   PetscErrorCode ierr;
2074 
2075   PetscFunctionBegin;
2076   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2077   ierr = PetscSFGetRanks(sf, nranks, ranks, NULL, NULL, NULL);CHKERRQ(ierr);
2078   PetscFunctionReturn(0);
2079 }
2080 
2081 static PetscErrorCode DMInitialize_Plex(DM dm)
2082 {
2083   PetscErrorCode ierr;
2084 
2085   PetscFunctionBegin;
2086   dm->ops->view                            = DMView_Plex;
2087   dm->ops->load                            = DMLoad_Plex;
2088   dm->ops->setfromoptions                  = DMSetFromOptions_Plex;
2089   dm->ops->clone                           = DMClone_Plex;
2090   dm->ops->setup                           = DMSetUp_Plex;
2091   dm->ops->createdefaultsection            = DMCreateDefaultSection_Plex;
2092   dm->ops->createdefaultconstraints        = DMCreateDefaultConstraints_Plex;
2093   dm->ops->createglobalvector              = DMCreateGlobalVector_Plex;
2094   dm->ops->createlocalvector               = DMCreateLocalVector_Plex;
2095   dm->ops->getlocaltoglobalmapping         = NULL;
2096   dm->ops->createfieldis                   = NULL;
2097   dm->ops->createcoordinatedm              = DMCreateCoordinateDM_Plex;
2098   dm->ops->getcoloring                     = NULL;
2099   dm->ops->creatematrix                    = DMCreateMatrix_Plex;
2100   dm->ops->createinterpolation             = DMCreateInterpolation_Plex;
2101   dm->ops->getaggregates                   = NULL;
2102   dm->ops->getinjection                    = DMCreateInjection_Plex;
2103   dm->ops->refine                          = DMRefine_Plex;
2104   dm->ops->coarsen                         = DMCoarsen_Plex;
2105   dm->ops->refinehierarchy                 = DMRefineHierarchy_Plex;
2106   dm->ops->coarsenhierarchy                = DMCoarsenHierarchy_Plex;
2107   dm->ops->adaptlabel                      = DMAdaptLabel_Plex;
2108   dm->ops->adaptmetric                     = DMAdaptMetric_Plex;
2109   dm->ops->globaltolocalbegin              = NULL;
2110   dm->ops->globaltolocalend                = NULL;
2111   dm->ops->localtoglobalbegin              = NULL;
2112   dm->ops->localtoglobalend                = NULL;
2113   dm->ops->destroy                         = DMDestroy_Plex;
2114   dm->ops->createsubdm                     = DMCreateSubDM_Plex;
2115   dm->ops->getdimpoints                    = DMGetDimPoints_Plex;
2116   dm->ops->locatepoints                    = DMLocatePoints_Plex;
2117   dm->ops->projectfunctionlocal            = DMProjectFunctionLocal_Plex;
2118   dm->ops->projectfunctionlabellocal       = DMProjectFunctionLabelLocal_Plex;
2119   dm->ops->projectfieldlocal               = DMProjectFieldLocal_Plex;
2120   dm->ops->projectfieldlabellocal          = DMProjectFieldLabelLocal_Plex;
2121   dm->ops->computel2diff                   = DMComputeL2Diff_Plex;
2122   dm->ops->computel2gradientdiff           = DMComputeL2GradientDiff_Plex;
2123   dm->ops->computel2fielddiff              = DMComputeL2FieldDiff_Plex;
2124   dm->ops->getneighbors                    = DMGetNeighors_Plex;
2125   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C",DMPlexInsertBoundaryValues_Plex);CHKERRQ(ierr);
2126   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",DMSetUpGLVisViewer_Plex);CHKERRQ(ierr);
2127   PetscFunctionReturn(0);
2128 }
2129 
2130 PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
2131 {
2132   DM_Plex        *mesh = (DM_Plex *) dm->data;
2133   PetscErrorCode ierr;
2134 
2135   PetscFunctionBegin;
2136   mesh->refct++;
2137   (*newdm)->data = mesh;
2138   ierr = PetscObjectChangeTypeName((PetscObject) *newdm, DMPLEX);CHKERRQ(ierr);
2139   ierr = DMInitialize_Plex(*newdm);CHKERRQ(ierr);
2140   PetscFunctionReturn(0);
2141 }
2142 
2143 /*MC
2144   DMPLEX = "plex" - A DM object that encapsulates an unstructured mesh, or CW Complex, which can be expressed using a Hasse Diagram.
2145                     In the local representation, Vecs contain all unknowns in the interior and shared boundary. This is
2146                     specified by a PetscSection object. Ownership in the global representation is determined by
2147                     ownership of the underlying DMPlex points. This is specified by another PetscSection object.
2148 
2149   Level: intermediate
2150 
2151 .seealso: DMType, DMPlexCreate(), DMCreate(), DMSetType()
2152 M*/
2153 
2154 PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
2155 {
2156   DM_Plex        *mesh;
2157   PetscInt       unit, d;
2158   PetscErrorCode ierr;
2159 
2160   PetscFunctionBegin;
2161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2162   ierr     = PetscNewLog(dm,&mesh);CHKERRQ(ierr);
2163   dm->dim  = 0;
2164   dm->data = mesh;
2165 
2166   mesh->refct             = 1;
2167   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection);CHKERRQ(ierr);
2168   mesh->maxConeSize       = 0;
2169   mesh->cones             = NULL;
2170   mesh->coneOrientations  = NULL;
2171   ierr                    = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection);CHKERRQ(ierr);
2172   mesh->maxSupportSize    = 0;
2173   mesh->supports          = NULL;
2174   mesh->refinementUniform = PETSC_TRUE;
2175   mesh->refinementLimit   = -1.0;
2176 
2177   mesh->facesTmp = NULL;
2178 
2179   mesh->tetgenOpts   = NULL;
2180   mesh->triangleOpts = NULL;
2181   ierr = PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner);CHKERRQ(ierr);
2182   mesh->remeshBd     = PETSC_FALSE;
2183 
2184   mesh->subpointMap = NULL;
2185 
2186   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
2187 
2188   mesh->regularRefinement   = PETSC_FALSE;
2189   mesh->depthState          = -1;
2190   mesh->globalVertexNumbers = NULL;
2191   mesh->globalCellNumbers   = NULL;
2192   mesh->anchorSection       = NULL;
2193   mesh->anchorIS            = NULL;
2194   mesh->createanchors       = NULL;
2195   mesh->computeanchormatrix = NULL;
2196   mesh->parentSection       = NULL;
2197   mesh->parents             = NULL;
2198   mesh->childIDs            = NULL;
2199   mesh->childSection        = NULL;
2200   mesh->children            = NULL;
2201   mesh->referenceTree       = NULL;
2202   mesh->getchildsymmetry    = NULL;
2203   for (d = 0; d < 8; ++d) mesh->hybridPointMax[d] = PETSC_DETERMINE;
2204   mesh->vtkCellHeight       = 0;
2205   mesh->useCone             = PETSC_FALSE;
2206   mesh->useClosure          = PETSC_TRUE;
2207   mesh->useAnchors          = PETSC_FALSE;
2208 
2209   mesh->maxProjectionHeight = 0;
2210 
2211   mesh->printSetValues = PETSC_FALSE;
2212   mesh->printFEM       = 0;
2213   mesh->printTol       = 1.0e-10;
2214 
2215   ierr = DMInitialize_Plex(dm);CHKERRQ(ierr);
2216   PetscFunctionReturn(0);
2217 }
2218 
2219 /*@
2220   DMPlexCreate - Creates a DMPlex object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
2221 
2222   Collective on MPI_Comm
2223 
2224   Input Parameter:
2225 . comm - The communicator for the DMPlex object
2226 
2227   Output Parameter:
2228 . mesh  - The DMPlex object
2229 
2230   Level: beginner
2231 
2232 .keywords: DMPlex, create
2233 @*/
2234 PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
2235 {
2236   PetscErrorCode ierr;
2237 
2238   PetscFunctionBegin;
2239   PetscValidPointer(mesh,2);
2240   ierr = DMCreate(comm, mesh);CHKERRQ(ierr);
2241   ierr = DMSetType(*mesh, DMPLEX);CHKERRQ(ierr);
2242   PetscFunctionReturn(0);
2243 }
2244 
2245 /*
2246   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
2247 */
2248 static PetscErrorCode DMPlexBuildFromCellList_Parallel_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[], PetscSF *sfVert)
2249 {
2250   PetscSF         sfPoint;
2251   PetscLayout     vLayout;
2252   PetscHashI      vhash;
2253   PetscSFNode    *remoteVerticesAdj, *vertexLocal, *vertexOwner, *remoteVertex;
2254   const PetscInt *vrange;
2255   PetscInt        numVerticesAdj, off, *verticesAdj, numVerticesGhost = 0, *localVertex, *cone, c, p, v, g;
2256   PETSC_UNUSED PetscHashIIter ret, iter;
2257   PetscMPIInt     rank, size;
2258   PetscErrorCode  ierr;
2259 
2260   PetscFunctionBegin;
2261   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2262   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2263   /* Partition vertices */
2264   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) dm), &vLayout);CHKERRQ(ierr);
2265   ierr = PetscLayoutSetLocalSize(vLayout, numVertices);CHKERRQ(ierr);
2266   ierr = PetscLayoutSetBlockSize(vLayout, 1);CHKERRQ(ierr);
2267   ierr = PetscLayoutSetUp(vLayout);CHKERRQ(ierr);
2268   ierr = PetscLayoutGetRanges(vLayout, &vrange);CHKERRQ(ierr);
2269   /* Count vertices and map them to procs */
2270   PetscHashICreate(vhash);
2271   for (c = 0; c < numCells; ++c) {
2272     for (p = 0; p < numCorners; ++p) {
2273       PetscHashIPut(vhash, cells[c*numCorners+p], ret, iter);
2274     }
2275   }
2276   PetscHashISize(vhash, numVerticesAdj);
2277   ierr = PetscMalloc1(numVerticesAdj, &verticesAdj);CHKERRQ(ierr);
2278   off = 0; ierr = PetscHashIGetKeys(vhash, &off, verticesAdj);CHKERRQ(ierr);
2279   if (off != numVerticesAdj) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %D should be %D", off, numVerticesAdj);
2280   ierr = PetscSortInt(numVerticesAdj, verticesAdj);CHKERRQ(ierr);
2281   ierr = PetscMalloc1(numVerticesAdj, &remoteVerticesAdj);CHKERRQ(ierr);
2282   for (v = 0; v < numVerticesAdj; ++v) {
2283     const PetscInt gv = verticesAdj[v];
2284     PetscInt       vrank;
2285 
2286     ierr = PetscFindInt(gv, size+1, vrange, &vrank);CHKERRQ(ierr);
2287     vrank = vrank < 0 ? -(vrank+2) : vrank;
2288     remoteVerticesAdj[v].index = gv - vrange[vrank];
2289     remoteVerticesAdj[v].rank  = vrank;
2290   }
2291   /* Create cones */
2292   ierr = DMPlexSetChart(dm, 0, numCells+numVerticesAdj);CHKERRQ(ierr);
2293   for (c = 0; c < numCells; ++c) {ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);}
2294   ierr = DMSetUp(dm);CHKERRQ(ierr);
2295   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
2296   for (c = 0; c < numCells; ++c) {
2297     for (p = 0; p < numCorners; ++p) {
2298       const PetscInt gv = cells[c*numCorners+p];
2299       PetscInt       lv;
2300 
2301       ierr = PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv);CHKERRQ(ierr);
2302       if (lv < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %D in local connectivity", gv);
2303       cone[p] = lv+numCells;
2304     }
2305     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
2306   }
2307   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
2308   /* Create SF for vertices */
2309   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfVert);CHKERRQ(ierr);
2310   ierr = PetscObjectSetName((PetscObject) *sfVert, "Vertex Ownership SF");CHKERRQ(ierr);
2311   ierr = PetscSFSetFromOptions(*sfVert);CHKERRQ(ierr);
2312   ierr = PetscSFSetGraph(*sfVert, numVertices, numVerticesAdj, NULL, PETSC_OWN_POINTER, remoteVerticesAdj, PETSC_OWN_POINTER);CHKERRQ(ierr);
2313   ierr = PetscFree(verticesAdj);CHKERRQ(ierr);
2314   /* Build pointSF */
2315   ierr = PetscMalloc2(numVerticesAdj, &vertexLocal, numVertices, &vertexOwner);CHKERRQ(ierr);
2316   for (v = 0; v < numVerticesAdj; ++v) {vertexLocal[v].index = v+numCells; vertexLocal[v].rank = rank;}
2317   for (v = 0; v < numVertices;    ++v) {vertexOwner[v].index = -1;         vertexOwner[v].rank = -1;}
2318   ierr = PetscSFReduceBegin(*sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2319   ierr = PetscSFReduceEnd(*sfVert, MPIU_2INT, vertexLocal, vertexOwner, MPI_MAXLOC);CHKERRQ(ierr);
2320   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);
2321   ierr = PetscSFBcastBegin(*sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2322   ierr = PetscSFBcastEnd(*sfVert, MPIU_2INT, vertexOwner, vertexLocal);CHKERRQ(ierr);
2323   for (v = 0; v < numVerticesAdj; ++v) if (vertexLocal[v].rank != rank) ++numVerticesGhost;
2324   ierr = PetscMalloc1(numVerticesGhost, &localVertex);CHKERRQ(ierr);
2325   ierr = PetscMalloc1(numVerticesGhost, &remoteVertex);CHKERRQ(ierr);
2326   for (v = 0, g = 0; v < numVerticesAdj; ++v) {
2327     if (vertexLocal[v].rank != rank) {
2328       localVertex[g]        = v+numCells;
2329       remoteVertex[g].index = vertexLocal[v].index;
2330       remoteVertex[g].rank  = vertexLocal[v].rank;
2331       ++g;
2332     }
2333   }
2334   ierr = PetscFree2(vertexLocal, vertexOwner);CHKERRQ(ierr);
2335   if (g != numVerticesGhost) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of vertex ghosts %D should be %D", g, numVerticesGhost);
2336   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
2337   ierr = PetscObjectSetName((PetscObject) sfPoint, "point SF");CHKERRQ(ierr);
2338   ierr = PetscSFSetGraph(sfPoint, numCells+numVerticesAdj, numVerticesGhost, localVertex, PETSC_OWN_POINTER, remoteVertex, PETSC_OWN_POINTER);CHKERRQ(ierr);
2339   ierr = PetscLayoutDestroy(&vLayout);CHKERRQ(ierr);
2340   PetscHashIDestroy(vhash);
2341   /* Fill in the rest of the topology structure */
2342   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2343   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2344   PetscFunctionReturn(0);
2345 }
2346 
2347 /*
2348   This takes as input the coordinates for each owned vertex
2349 */
2350 static PetscErrorCode DMPlexBuildCoordinates_Parallel_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numV, PetscSF sfVert, const PetscReal vertexCoords[])
2351 {
2352   PetscSection   coordSection;
2353   Vec            coordinates;
2354   PetscScalar   *coords;
2355   PetscInt       numVertices, numVerticesAdj, coordSize, v;
2356   PetscErrorCode ierr;
2357 
2358   PetscFunctionBegin;
2359   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
2360   ierr = PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL);CHKERRQ(ierr);
2361   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2362   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2363   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
2364   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVerticesAdj);CHKERRQ(ierr);
2365   for (v = numCells; v < numCells+numVerticesAdj; ++v) {
2366     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
2367     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
2368   }
2369   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2370   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
2371   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
2372   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
2373   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2374   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2375   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
2376   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2377   {
2378     MPI_Datatype coordtype;
2379 
2380     /* Need a temp buffer for coords if we have complex/single */
2381     ierr = MPI_Type_contiguous(spaceDim, MPIU_SCALAR, &coordtype);CHKERRQ(ierr);
2382     ierr = MPI_Type_commit(&coordtype);CHKERRQ(ierr);
2383 #if defined(PETSC_USE_COMPLEX)
2384     {
2385     PetscScalar *svertexCoords;
2386     PetscInt    i;
2387     ierr = PetscMalloc1(numV*spaceDim,&svertexCoords);CHKERRQ(ierr);
2388     for (i=0; i<numV*spaceDim; i++) svertexCoords[i] = vertexCoords[i];
2389     ierr = PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
2390     ierr = PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords);CHKERRQ(ierr);
2391     ierr = PetscFree(svertexCoords);CHKERRQ(ierr);
2392     }
2393 #else
2394     ierr = PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
2395     ierr = PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords);CHKERRQ(ierr);
2396 #endif
2397     ierr = MPI_Type_free(&coordtype);CHKERRQ(ierr);
2398   }
2399   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2400   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
2401   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2402   PetscFunctionReturn(0);
2403 }
2404 
2405 /*@C
2406   DMPlexCreateFromCellListParallel - This takes as input common mesh generator output, a list of the vertices for each cell, and produces a DM
2407 
2408   Input Parameters:
2409 + comm - The communicator
2410 . dim - The topological dimension of the mesh
2411 . numCells - The number of cells owned by this process
2412 . numVertices - The number of vertices owned by this process
2413 . numCorners - The number of vertices for each cell
2414 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
2415 . cells - An array of numCells*numCorners numbers, the global vertex numbers for each cell
2416 . spaceDim - The spatial dimension used for coordinates
2417 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
2418 
2419   Output Parameter:
2420 + dm - The DM
2421 - vertexSF - Optional, SF describing complete vertex ownership
2422 
2423   Note: Two triangles sharing a face
2424 $
2425 $        2
2426 $      / | \
2427 $     /  |  \
2428 $    /   |   \
2429 $   0  0 | 1  3
2430 $    \   |   /
2431 $     \  |  /
2432 $      \ | /
2433 $        1
2434 would have input
2435 $  numCells = 2, numVertices = 4
2436 $  cells = [0 1 2  1 3 2]
2437 $
2438 which would result in the DMPlex
2439 $
2440 $        4
2441 $      / | \
2442 $     /  |  \
2443 $    /   |   \
2444 $   2  0 | 1  5
2445 $    \   |   /
2446 $     \  |  /
2447 $      \ | /
2448 $        3
2449 
2450   Level: beginner
2451 
2452 .seealso: DMPlexCreateFromCellList(), DMPlexCreateFromDAG(), DMPlexCreate()
2453 @*/
2454 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)
2455 {
2456   PetscSF        sfVert;
2457   PetscErrorCode ierr;
2458 
2459   PetscFunctionBegin;
2460   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
2461   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
2462   PetscValidLogicalCollectiveInt(*dm, dim, 2);
2463   PetscValidLogicalCollectiveInt(*dm, spaceDim, 8);
2464   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
2465   ierr = DMPlexBuildFromCellList_Parallel_Private(*dm, numCells, numVertices, numCorners, cells, &sfVert);CHKERRQ(ierr);
2466   if (interpolate) {
2467     DM idm = NULL;
2468 
2469     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2470     ierr = DMDestroy(dm);CHKERRQ(ierr);
2471     *dm  = idm;
2472   }
2473   ierr = DMPlexBuildCoordinates_Parallel_Private(*dm, spaceDim, numCells, numVertices,sfVert, vertexCoords);CHKERRQ(ierr);
2474   if (vertexSF) *vertexSF = sfVert;
2475   else {ierr = PetscSFDestroy(&sfVert);CHKERRQ(ierr);}
2476   PetscFunctionReturn(0);
2477 }
2478 
2479 /*
2480   This takes as input the common mesh generator output, a list of the vertices for each cell
2481 */
2482 static PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
2483 {
2484   PetscInt      *cone, c, p;
2485   PetscErrorCode ierr;
2486 
2487   PetscFunctionBegin;
2488   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
2489   for (c = 0; c < numCells; ++c) {
2490     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
2491   }
2492   ierr = DMSetUp(dm);CHKERRQ(ierr);
2493   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
2494   for (c = 0; c < numCells; ++c) {
2495     for (p = 0; p < numCorners; ++p) {
2496       cone[p] = cells[c*numCorners+p]+numCells;
2497     }
2498     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
2499   }
2500   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
2501   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2502   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 /*
2507   This takes as input the coordinates for each vertex
2508 */
2509 static PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
2510 {
2511   PetscSection   coordSection;
2512   Vec            coordinates;
2513   DM             cdm;
2514   PetscScalar   *coords;
2515   PetscInt       v, d;
2516   PetscErrorCode ierr;
2517 
2518   PetscFunctionBegin;
2519   ierr = DMSetCoordinateDim(dm, spaceDim);CHKERRQ(ierr);
2520   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2521   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2522   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
2523   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
2524   for (v = numCells; v < numCells+numVertices; ++v) {
2525     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
2526     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
2527   }
2528   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2529 
2530   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
2531   ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
2532   ierr = VecSetBlockSize(coordinates, spaceDim);CHKERRQ(ierr);
2533   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2534   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2535   for (v = 0; v < numVertices; ++v) {
2536     for (d = 0; d < spaceDim; ++d) {
2537       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
2538     }
2539   }
2540   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2541   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
2542   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2543   PetscFunctionReturn(0);
2544 }
2545 
2546 /*@C
2547   DMPlexCreateFromCellList - This takes as input common mesh generator output, a list of the vertices for each cell, and produces a DM
2548 
2549   Input Parameters:
2550 + comm - The communicator
2551 . dim - The topological dimension of the mesh
2552 . numCells - The number of cells
2553 . numVertices - The number of vertices
2554 . numCorners - The number of vertices for each cell
2555 . interpolate - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
2556 . cells - An array of numCells*numCorners numbers, the vertices for each cell
2557 . spaceDim - The spatial dimension used for coordinates
2558 - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
2559 
2560   Output Parameter:
2561 . dm - The DM
2562 
2563   Note: Two triangles sharing a face
2564 $
2565 $        2
2566 $      / | \
2567 $     /  |  \
2568 $    /   |   \
2569 $   0  0 | 1  3
2570 $    \   |   /
2571 $     \  |  /
2572 $      \ | /
2573 $        1
2574 would have input
2575 $  numCells = 2, numVertices = 4
2576 $  cells = [0 1 2  1 3 2]
2577 $
2578 which would result in the DMPlex
2579 $
2580 $        4
2581 $      / | \
2582 $     /  |  \
2583 $    /   |   \
2584 $   2  0 | 1  5
2585 $    \   |   /
2586 $     \  |  /
2587 $      \ | /
2588 $        3
2589 
2590   Level: beginner
2591 
2592 .seealso: DMPlexCreateFromDAG(), DMPlexCreate()
2593 @*/
2594 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)
2595 {
2596   PetscErrorCode ierr;
2597 
2598   PetscFunctionBegin;
2599   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
2600   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
2601   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
2602   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
2603   if (interpolate) {
2604     DM idm = NULL;
2605 
2606     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
2607     ierr = DMDestroy(dm);CHKERRQ(ierr);
2608     *dm  = idm;
2609   }
2610   ierr = DMPlexBuildCoordinates_Private(*dm, spaceDim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
2611   PetscFunctionReturn(0);
2612 }
2613 
2614 /*@
2615   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a DM
2616 
2617   Input Parameters:
2618 + dm - The empty DM object, usually from DMCreate() and DMSetDimension()
2619 . depth - The depth of the DAG
2620 . numPoints - The number of points at each depth
2621 . coneSize - The cone size of each point
2622 . cones - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
2623 . coneOrientations - The orientation of each cone point
2624 - vertexCoords - An array of numVertices*dim numbers, the coordinates of each vertex
2625 
2626   Output Parameter:
2627 . dm - The DM
2628 
2629   Note: Two triangles sharing a face would have input
2630 $  depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
2631 $  cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
2632 $ vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
2633 $
2634 which would result in the DMPlex
2635 $
2636 $        4
2637 $      / | \
2638 $     /  |  \
2639 $    /   |   \
2640 $   2  0 | 1  5
2641 $    \   |   /
2642 $     \  |  /
2643 $      \ | /
2644 $        3
2645 $
2646 $ Notice that all points are numbered consecutively, unlikely DMPlexCreateFromCellList()
2647 
2648   Level: advanced
2649 
2650 .seealso: DMPlexCreateFromCellList(), DMPlexCreate()
2651 @*/
2652 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
2653 {
2654   Vec            coordinates;
2655   PetscSection   coordSection;
2656   PetscScalar    *coords;
2657   PetscInt       coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
2658   PetscErrorCode ierr;
2659 
2660   PetscFunctionBegin;
2661   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
2662   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
2663   if (dimEmbed < dim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Embedding dimension %d cannot be less than intrinsic dimension %d",dimEmbed,dim);
2664   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
2665   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
2666   for (p = pStart; p < pEnd; ++p) {
2667     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
2668     if (firstVertex < 0 && !coneSize[p - pStart]) {
2669       firstVertex = p - pStart;
2670     }
2671   }
2672   if (firstVertex < 0 && numPoints[0]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected %d vertices but could not find any", numPoints[0]);
2673   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
2674   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
2675     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
2676     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
2677   }
2678   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
2679   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
2680   /* Build coordinates */
2681   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2682   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
2683   ierr = PetscSectionSetFieldComponents(coordSection, 0, dimEmbed);CHKERRQ(ierr);
2684   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
2685   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
2686     ierr = PetscSectionSetDof(coordSection, v, dimEmbed);CHKERRQ(ierr);
2687     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed);CHKERRQ(ierr);
2688   }
2689   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
2690   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
2691   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
2692   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
2693   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2694   ierr = VecSetBlockSize(coordinates, dimEmbed);CHKERRQ(ierr);
2695   ierr = VecSetType(coordinates,VECSTANDARD);CHKERRQ(ierr);
2696   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2697   for (v = 0; v < numPoints[0]; ++v) {
2698     PetscInt off;
2699 
2700     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
2701     for (d = 0; d < dimEmbed; ++d) {
2702       coords[off+d] = vertexCoords[v*dimEmbed+d];
2703     }
2704   }
2705   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2706   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
2707   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
2708   PetscFunctionReturn(0);
2709 }
2710 
2711 /*@C
2712   DMPlexCreateFromFile - This takes a filename and produces a DM
2713 
2714   Input Parameters:
2715 + comm - The communicator
2716 . filename - A file name
2717 - interpolate - Flag to create intermediate mesh pieces (edges, faces)
2718 
2719   Output Parameter:
2720 . dm - The DM
2721 
2722   Level: beginner
2723 
2724 .seealso: DMPlexCreateFromDAG(), DMPlexCreateFromCellList(), DMPlexCreate()
2725 @*/
2726 PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
2727 {
2728   const char    *extGmsh    = ".msh";
2729   const char    *extCGNS    = ".cgns";
2730   const char    *extExodus  = ".exo";
2731   const char    *extGenesis = ".gen";
2732   const char    *extFluent  = ".cas";
2733   const char    *extHDF5    = ".h5";
2734   const char    *extMed     = ".med";
2735   const char    *extPLY     = ".ply";
2736   size_t         len;
2737   PetscBool      isGmsh, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isMed, isPLY;
2738   PetscMPIInt    rank;
2739   PetscErrorCode ierr;
2740 
2741   PetscFunctionBegin;
2742   PetscValidPointer(filename, 2);
2743   PetscValidPointer(dm, 4);
2744   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2745   ierr = PetscStrlen(filename, &len);CHKERRQ(ierr);
2746   if (!len) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
2747   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGmsh,    4, &isGmsh);CHKERRQ(ierr);
2748   ierr = PetscStrncmp(&filename[PetscMax(0,len-5)], extCGNS,    5, &isCGNS);CHKERRQ(ierr);
2749   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extExodus,  4, &isExodus);CHKERRQ(ierr);
2750   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extGenesis, 4, &isGenesis);CHKERRQ(ierr);
2751   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extFluent,  4, &isFluent);CHKERRQ(ierr);
2752   ierr = PetscStrncmp(&filename[PetscMax(0,len-3)], extHDF5,    3, &isHDF5);CHKERRQ(ierr);
2753   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extMed,     4, &isMed);CHKERRQ(ierr);
2754   ierr = PetscStrncmp(&filename[PetscMax(0,len-4)], extPLY,     4, &isPLY);CHKERRQ(ierr);
2755   if (isGmsh) {
2756     ierr = DMPlexCreateGmshFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2757   } else if (isCGNS) {
2758     ierr = DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2759   } else if (isExodus || isGenesis) {
2760     ierr = DMPlexCreateExodusFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2761   } else if (isFluent) {
2762     ierr = DMPlexCreateFluentFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2763   } else if (isHDF5) {
2764     PetscViewer viewer;
2765 
2766     ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
2767     ierr = PetscViewerSetType(viewer, PETSCVIEWERHDF5);CHKERRQ(ierr);
2768     ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
2769     ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
2770     ierr = DMCreate(comm, dm);CHKERRQ(ierr);
2771     ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
2772     ierr = DMLoad(*dm, viewer);CHKERRQ(ierr);
2773     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
2774   } else if (isMed) {
2775     ierr = DMPlexCreateMedFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2776   } else if (isPLY) {
2777     ierr = DMPlexCreatePLYFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr);
2778   } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
2779   PetscFunctionReturn(0);
2780 }
2781 
2782 /*@
2783   DMPlexCreateReferenceCell - Create a DMPLEX with the appropriate FEM reference cell
2784 
2785   Collective on comm
2786 
2787   Input Parameters:
2788 + comm    - The communicator
2789 . dim     - The spatial dimension
2790 - simplex - Flag for simplex, otherwise use a tensor-product cell
2791 
2792   Output Parameter:
2793 . refdm - The reference cell
2794 
2795   Level: intermediate
2796 
2797 .keywords: reference cell
2798 .seealso:
2799 @*/
2800 PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, PetscInt dim, PetscBool simplex, DM *refdm)
2801 {
2802   DM             rdm;
2803   Vec            coords;
2804   PetscErrorCode ierr;
2805 
2806   PetscFunctionBeginUser;
2807   ierr = DMCreate(comm, &rdm);CHKERRQ(ierr);
2808   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
2809   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
2810   switch (dim) {
2811   case 0:
2812   {
2813     PetscInt    numPoints[1]        = {1};
2814     PetscInt    coneSize[1]         = {0};
2815     PetscInt    cones[1]            = {0};
2816     PetscInt    coneOrientations[1] = {0};
2817     PetscScalar vertexCoords[1]     = {0.0};
2818 
2819     ierr = DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2820   }
2821   break;
2822   case 1:
2823   {
2824     PetscInt    numPoints[2]        = {2, 1};
2825     PetscInt    coneSize[3]         = {2, 0, 0};
2826     PetscInt    cones[2]            = {1, 2};
2827     PetscInt    coneOrientations[2] = {0, 0};
2828     PetscScalar vertexCoords[2]     = {-1.0,  1.0};
2829 
2830     ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2831   }
2832   break;
2833   case 2:
2834     if (simplex) {
2835       PetscInt    numPoints[2]        = {3, 1};
2836       PetscInt    coneSize[4]         = {3, 0, 0, 0};
2837       PetscInt    cones[3]            = {1, 2, 3};
2838       PetscInt    coneOrientations[3] = {0, 0, 0};
2839       PetscScalar vertexCoords[6]     = {-1.0, -1.0,  1.0, -1.0,  -1.0, 1.0};
2840 
2841       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2842     } else {
2843       PetscInt    numPoints[2]        = {4, 1};
2844       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
2845       PetscInt    cones[4]            = {1, 2, 3, 4};
2846       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
2847       PetscScalar vertexCoords[8]     = {-1.0, -1.0,  1.0, -1.0,  1.0, 1.0,  -1.0, 1.0};
2848 
2849       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2850     }
2851   break;
2852   case 3:
2853     if (simplex) {
2854       PetscInt    numPoints[2]        = {4, 1};
2855       PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
2856       PetscInt    cones[4]            = {1, 3, 2, 4};
2857       PetscInt    coneOrientations[4] = {0, 0, 0, 0};
2858       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};
2859 
2860       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2861     } else {
2862       PetscInt    numPoints[2]        = {8, 1};
2863       PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
2864       PetscInt    cones[8]            = {1, 4, 3, 2, 5, 6, 7, 8};
2865       PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
2866       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,
2867                                          -1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0, 1.0,  1.0,  -1.0, 1.0,  1.0};
2868 
2869       ierr = DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords);CHKERRQ(ierr);
2870     }
2871   break;
2872   default:
2873     SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Cannot create reference cell for dimension %d", dim);
2874   }
2875   *refdm = NULL;
2876   ierr = DMPlexInterpolate(rdm, refdm);CHKERRQ(ierr);
2877   if (rdm->coordinateDM) {
2878     DM           ncdm;
2879     PetscSection cs;
2880     PetscInt     pEnd = -1;
2881 
2882     ierr = DMGetDefaultSection(rdm->coordinateDM, &cs);CHKERRQ(ierr);
2883     if (cs) {ierr = PetscSectionGetChart(cs, NULL, &pEnd);CHKERRQ(ierr);}
2884     if (pEnd >= 0) {
2885       ierr = DMClone(rdm->coordinateDM, &ncdm);CHKERRQ(ierr);
2886       ierr = DMSetDefaultSection(ncdm, cs);CHKERRQ(ierr);
2887       ierr = DMSetCoordinateDM(*refdm, ncdm);CHKERRQ(ierr);
2888       ierr = DMDestroy(&ncdm);CHKERRQ(ierr);
2889     }
2890   }
2891   ierr = DMGetCoordinatesLocal(rdm, &coords);CHKERRQ(ierr);
2892   if (coords) {
2893     ierr = DMSetCoordinatesLocal(*refdm, coords);CHKERRQ(ierr);
2894   } else {
2895     ierr = DMGetCoordinates(rdm, &coords);CHKERRQ(ierr);
2896     if (coords) {ierr = DMSetCoordinates(*refdm, coords);CHKERRQ(ierr);}
2897   }
2898   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
2899   PetscFunctionReturn(0);
2900 }
2901