xref: /petsc/src/dm/impls/plex/plexgenerate.c (revision efd4aadf157bf1ba2d80c2be092fcf4247860003)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 
3 PetscErrorCode DMPlexInvertCell_Internal(PetscInt dim, PetscInt numCorners, PetscInt cone[])
4 {
5   int tmpc;
6 
7   PetscFunctionBegin;
8   if (dim != 3) PetscFunctionReturn(0);
9   switch (numCorners) {
10   case 4:
11     tmpc    = cone[0];
12     cone[0] = cone[1];
13     cone[1] = tmpc;
14     break;
15   case 8:
16     tmpc    = cone[1];
17     cone[1] = cone[3];
18     cone[3] = tmpc;
19     break;
20   default: break;
21   }
22   PetscFunctionReturn(0);
23 }
24 
25 /*@C
26   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
27 
28   Input Parameters:
29 + numCorners - The number of vertices in a cell
30 - cone - The incoming cone
31 
32   Output Parameter:
33 . cone - The inverted cone (in-place)
34 
35   Level: developer
36 
37 .seealso: DMPlexGenerate()
38 @*/
39 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
40 {
41   int tmpc;
42 
43   PetscFunctionBegin;
44   if (dim != 3) PetscFunctionReturn(0);
45   switch (numCorners) {
46   case 4:
47     tmpc    = cone[0];
48     cone[0] = cone[1];
49     cone[1] = tmpc;
50     break;
51   case 8:
52     tmpc    = cone[1];
53     cone[1] = cone[3];
54     cone[3] = tmpc;
55     break;
56   default: break;
57   }
58   PetscFunctionReturn(0);
59 }
60 
61 /* This is to fix the tetrahedron orientation from TetGen */
62 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
63 {
64   PetscInt       bound = numCells*numCorners, coff;
65   PetscErrorCode ierr;
66 
67   PetscFunctionBegin;
68   for (coff = 0; coff < bound; coff += numCorners) {
69     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
70   }
71   PetscFunctionReturn(0);
72 }
73 
74 /*@C
75   DMPlexTriangleSetOptions - Set the options used for the Triangle mesh generator
76 
77   Not Collective
78 
79   Inputs Parameters:
80 + dm - The DMPlex object
81 - opts - The command line options
82 
83   Level: developer
84 
85 .keywords: mesh, points
86 .seealso: DMPlexTetgenSetOptions(), DMPlexGenerate()
87 @*/
88 PetscErrorCode DMPlexTriangleSetOptions(DM dm, const char *opts)
89 {
90   DM_Plex       *mesh = (DM_Plex*) dm->data;
91   PetscErrorCode ierr;
92 
93   PetscFunctionBegin;
94   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
95   PetscValidPointer(opts, 2);
96   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
97   ierr = PetscStrallocpy(opts, &mesh->triangleOpts);CHKERRQ(ierr);
98   PetscFunctionReturn(0);
99 }
100 
101 /*@C
102   DMPlexTetgenSetOptions - Set the options used for the Tetgen mesh generator
103 
104   Not Collective
105 
106   Inputs Parameters:
107 + dm - The DMPlex object
108 - opts - The command line options
109 
110   Level: developer
111 
112 .keywords: mesh, points
113 .seealso: DMPlexTriangleSetOptions(), DMPlexGenerate()
114 @*/
115 PetscErrorCode DMPlexTetgenSetOptions(DM dm, const char *opts)
116 {
117   DM_Plex       *mesh = (DM_Plex*) dm->data;
118   PetscErrorCode ierr;
119 
120   PetscFunctionBegin;
121   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
122   PetscValidPointer(opts, 2);
123   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
124   ierr = PetscStrallocpy(opts, &mesh->tetgenOpts);CHKERRQ(ierr);
125   PetscFunctionReturn(0);
126 }
127 
128 #if defined(PETSC_HAVE_TRIANGLE)
129 #include <triangle.h>
130 
131 static PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
132 {
133   PetscFunctionBegin;
134   inputCtx->numberofpoints             = 0;
135   inputCtx->numberofpointattributes    = 0;
136   inputCtx->pointlist                  = NULL;
137   inputCtx->pointattributelist         = NULL;
138   inputCtx->pointmarkerlist            = NULL;
139   inputCtx->numberofsegments           = 0;
140   inputCtx->segmentlist                = NULL;
141   inputCtx->segmentmarkerlist          = NULL;
142   inputCtx->numberoftriangleattributes = 0;
143   inputCtx->trianglelist               = NULL;
144   inputCtx->numberofholes              = 0;
145   inputCtx->holelist                   = NULL;
146   inputCtx->numberofregions            = 0;
147   inputCtx->regionlist                 = NULL;
148   PetscFunctionReturn(0);
149 }
150 
151 static PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
152 {
153   PetscFunctionBegin;
154   outputCtx->numberofpoints        = 0;
155   outputCtx->pointlist             = NULL;
156   outputCtx->pointattributelist    = NULL;
157   outputCtx->pointmarkerlist       = NULL;
158   outputCtx->numberoftriangles     = 0;
159   outputCtx->trianglelist          = NULL;
160   outputCtx->triangleattributelist = NULL;
161   outputCtx->neighborlist          = NULL;
162   outputCtx->segmentlist           = NULL;
163   outputCtx->segmentmarkerlist     = NULL;
164   outputCtx->numberofedges         = 0;
165   outputCtx->edgelist              = NULL;
166   outputCtx->edgemarkerlist        = NULL;
167   PetscFunctionReturn(0);
168 }
169 
170 static PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
171 {
172   PetscFunctionBegin;
173   free(outputCtx->pointlist);
174   free(outputCtx->pointmarkerlist);
175   free(outputCtx->segmentlist);
176   free(outputCtx->segmentmarkerlist);
177   free(outputCtx->edgelist);
178   free(outputCtx->edgemarkerlist);
179   free(outputCtx->trianglelist);
180   free(outputCtx->neighborlist);
181   PetscFunctionReturn(0);
182 }
183 
184 static PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
185 {
186   MPI_Comm             comm;
187   DM_Plex             *mesh             = (DM_Plex *) boundary->data;
188   PetscInt             dim              = 2;
189   const PetscBool      createConvexHull = PETSC_FALSE;
190   const PetscBool      constrained      = PETSC_FALSE;
191   const char          *labelName        = "marker";
192   const char          *labelName2       = "Face Sets";
193   struct triangulateio in;
194   struct triangulateio out;
195   DMLabel              label, label2;
196   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
197   PetscMPIInt          rank;
198   PetscErrorCode       ierr;
199 
200   PetscFunctionBegin;
201   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
202   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
203   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
204   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
205   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
206   ierr = DMGetLabel(boundary, labelName,  &label);CHKERRQ(ierr);
207   ierr = DMGetLabel(boundary, labelName2, &label2);CHKERRQ(ierr);
208 
209   in.numberofpoints = vEnd - vStart;
210   if (in.numberofpoints > 0) {
211     PetscSection coordSection;
212     Vec          coordinates;
213     PetscScalar *array;
214 
215     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
216     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
217     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
218     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
219     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
220     for (v = vStart; v < vEnd; ++v) {
221       const PetscInt idx = v - vStart;
222       PetscInt       off, d;
223 
224       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
225       for (d = 0; d < dim; ++d) {
226         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
227       }
228       if (label) {ierr = DMLabelGetValue(label, v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);}
229     }
230     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
231   }
232   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
233   in.numberofsegments = eEnd - eStart;
234   if (in.numberofsegments > 0) {
235     ierr = PetscMalloc1(in.numberofsegments*2, &in.segmentlist);CHKERRQ(ierr);
236     ierr = PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);CHKERRQ(ierr);
237     for (e = eStart; e < eEnd; ++e) {
238       const PetscInt  idx = e - eStart;
239       const PetscInt *cone;
240 
241       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
242 
243       in.segmentlist[idx*2+0] = cone[0] - vStart;
244       in.segmentlist[idx*2+1] = cone[1] - vStart;
245 
246       if (label) {ierr = DMLabelGetValue(label, e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);}
247     }
248   }
249 #if 0 /* Do not currently support holes */
250   PetscReal *holeCoords;
251   PetscInt   h, d;
252 
253   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
254   if (in.numberofholes > 0) {
255     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
256     for (h = 0; h < in.numberofholes; ++h) {
257       for (d = 0; d < dim; ++d) {
258         in.holelist[h*dim+d] = holeCoords[h*dim+d];
259       }
260     }
261   }
262 #endif
263   if (!rank) {
264     char args[32];
265 
266     /* Take away 'Q' for verbose output */
267     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
268     if (createConvexHull)   {ierr = PetscStrcat(args, "c");CHKERRQ(ierr);}
269     if (constrained)        {ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);}
270     if (mesh->triangleOpts) {triangulate(mesh->triangleOpts, &in, &out, NULL);}
271     else                    {triangulate(args, &in, &out, NULL);}
272   }
273   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
274   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
275   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
276   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
277   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
278 
279   {
280     DMLabel        glabel      = NULL;
281     DMLabel        glabel2     = NULL;
282     const PetscInt numCorners  = 3;
283     const PetscInt numCells    = out.numberoftriangles;
284     const PetscInt numVertices = out.numberofpoints;
285     const int     *cells      = out.trianglelist;
286     const double  *meshCoords = out.pointlist;
287 
288     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
289     if (label)  {ierr = DMCreateLabel(*dm, labelName);  ierr = DMGetLabel(*dm, labelName,  &glabel);}
290     if (label2) {ierr = DMCreateLabel(*dm, labelName2); ierr = DMGetLabel(*dm, labelName2, &glabel2);}
291     /* Set labels */
292     for (v = 0; v < numVertices; ++v) {
293       if (out.pointmarkerlist[v]) {
294         if (glabel) {ierr = DMLabelSetValue(glabel, v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);}
295       }
296     }
297     if (interpolate) {
298       for (e = 0; e < out.numberofedges; e++) {
299         if (out.edgemarkerlist[e]) {
300           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
301           const PetscInt *edges;
302           PetscInt        numEdges;
303 
304           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
305           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
306           if (glabel)  {ierr = DMLabelSetValue(glabel,  edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);}
307           if (glabel2) {ierr = DMLabelSetValue(glabel2, edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);}
308           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
309         }
310       }
311     }
312     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
313   }
314 #if 0 /* Do not currently support holes */
315   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
316 #endif
317   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 static PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
322 {
323   MPI_Comm             comm;
324   PetscInt             dim       = 2;
325   const char          *labelName = "marker";
326   struct triangulateio in;
327   struct triangulateio out;
328   DMLabel              label;
329   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
330   PetscMPIInt          rank;
331   PetscErrorCode       ierr;
332 
333   PetscFunctionBegin;
334   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
335   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
336   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
337   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
338   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
339   ierr = MPIU_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
340   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
341   ierr = DMGetLabel(dm, labelName, &label);CHKERRQ(ierr);
342 
343   in.numberofpoints = vEnd - vStart;
344   if (in.numberofpoints > 0) {
345     PetscSection coordSection;
346     Vec          coordinates;
347     PetscScalar *array;
348 
349     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
350     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
351     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
352     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
353     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
354     for (v = vStart; v < vEnd; ++v) {
355       const PetscInt idx = v - vStart;
356       PetscInt       off, d;
357 
358       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
359       for (d = 0; d < dim; ++d) {
360         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
361       }
362       if (label) {ierr = DMLabelGetValue(label, v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);}
363     }
364     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
365   }
366   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
367 
368   in.numberofcorners   = 3;
369   in.numberoftriangles = cEnd - cStart;
370 
371   in.trianglearealist  = (double*) maxVolumes;
372   if (in.numberoftriangles > 0) {
373     ierr = PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);CHKERRQ(ierr);
374     for (c = cStart; c < cEnd; ++c) {
375       const PetscInt idx      = c - cStart;
376       PetscInt      *closure = NULL;
377       PetscInt       closureSize;
378 
379       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
380       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
381       for (v = 0; v < 3; ++v) {
382         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
383       }
384       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
385     }
386   }
387   /* TODO: Segment markers are missing on input */
388 #if 0 /* Do not currently support holes */
389   PetscReal *holeCoords;
390   PetscInt   h, d;
391 
392   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
393   if (in.numberofholes > 0) {
394     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
395     for (h = 0; h < in.numberofholes; ++h) {
396       for (d = 0; d < dim; ++d) {
397         in.holelist[h*dim+d] = holeCoords[h*dim+d];
398       }
399     }
400   }
401 #endif
402   if (!rank) {
403     char args[32];
404 
405     /* Take away 'Q' for verbose output */
406     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
407     triangulate(args, &in, &out, NULL);
408   }
409   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
410   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
411   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
412   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
413   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
414 
415   {
416     DMLabel        rlabel      = NULL;
417     const PetscInt numCorners  = 3;
418     const PetscInt numCells    = out.numberoftriangles;
419     const PetscInt numVertices = out.numberofpoints;
420     const int     *cells      = out.trianglelist;
421     const double  *meshCoords = out.pointlist;
422     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
423 
424     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
425     if (label) {ierr = DMCreateLabel(*dmRefined, labelName); ierr = DMGetLabel(*dmRefined, labelName, &rlabel);}
426     /* Set labels */
427     for (v = 0; v < numVertices; ++v) {
428       if (out.pointmarkerlist[v]) {
429         if (rlabel) {ierr = DMLabelSetValue(rlabel, v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);}
430       }
431     }
432     if (interpolate) {
433       PetscInt e;
434 
435       for (e = 0; e < out.numberofedges; e++) {
436         if (out.edgemarkerlist[e]) {
437           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
438           const PetscInt *edges;
439           PetscInt        numEdges;
440 
441           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
442           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
443           if (rlabel) {ierr = DMLabelSetValue(rlabel, edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);}
444           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
445         }
446       }
447     }
448     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
449   }
450 #if 0 /* Do not currently support holes */
451   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
452 #endif
453   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
454   PetscFunctionReturn(0);
455 }
456 #endif /* PETSC_HAVE_TRIANGLE */
457 
458 #if defined(PETSC_HAVE_TETGEN)
459 #include <tetgen.h>
460 static PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
461 {
462   MPI_Comm       comm;
463   DM_Plex       *mesh      = (DM_Plex *) boundary->data;
464   const PetscInt dim       = 3;
465   const char    *labelName = "marker";
466   ::tetgenio     in;
467   ::tetgenio     out;
468   DMLabel        label;
469   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
470   PetscMPIInt    rank;
471   PetscErrorCode ierr;
472 
473   PetscFunctionBegin;
474   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
475   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
476   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
477   ierr = DMGetLabel(boundary, labelName, &label);CHKERRQ(ierr);
478 
479   in.numberofpoints = vEnd - vStart;
480   if (in.numberofpoints > 0) {
481     PetscSection coordSection;
482     Vec          coordinates;
483     PetscScalar *array;
484 
485     in.pointlist       = new double[in.numberofpoints*dim];
486     in.pointmarkerlist = new int[in.numberofpoints];
487 
488     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
489     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
490     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
491     for (v = vStart; v < vEnd; ++v) {
492       const PetscInt idx = v - vStart;
493       PetscInt       off, d;
494 
495       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
496       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
497       if (label) {
498         PetscInt val;
499 
500         ierr = DMLabelGetValue(label, v, &val);CHKERRQ(ierr);
501         in.pointmarkerlist[idx] = (int) val;
502       }
503     }
504     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
505   }
506   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
507 
508   in.numberoffacets = fEnd - fStart;
509   if (in.numberoffacets > 0) {
510     in.facetlist       = new tetgenio::facet[in.numberoffacets];
511     in.facetmarkerlist = new int[in.numberoffacets];
512     for (f = fStart; f < fEnd; ++f) {
513       const PetscInt idx     = f - fStart;
514       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
515 
516       in.facetlist[idx].numberofpolygons = 1;
517       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
518       in.facetlist[idx].numberofholes    = 0;
519       in.facetlist[idx].holelist         = NULL;
520 
521       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
522       for (p = 0; p < numPoints*2; p += 2) {
523         const PetscInt point = points[p];
524         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
525       }
526 
527       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
528       poly->numberofvertices = numVertices;
529       poly->vertexlist       = new int[poly->numberofvertices];
530       for (v = 0; v < numVertices; ++v) {
531         const PetscInt vIdx = points[v] - vStart;
532         poly->vertexlist[v] = vIdx;
533       }
534       if (label) {
535         PetscInt val;
536 
537         ierr = DMLabelGetValue(label, f, &val);CHKERRQ(ierr);
538         in.facetmarkerlist[idx] = (int) val;
539       }
540       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
541     }
542   }
543   if (!rank) {
544     char args[32];
545 
546     /* Take away 'Q' for verbose output */
547     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
548     if (mesh->tetgenOpts) {::tetrahedralize(mesh->tetgenOpts, &in, &out);}
549     else                  {::tetrahedralize(args, &in, &out);}
550   }
551   {
552     DMLabel        glabel      = NULL;
553     const PetscInt numCorners  = 4;
554     const PetscInt numCells    = out.numberoftetrahedra;
555     const PetscInt numVertices = out.numberofpoints;
556     const double   *meshCoords = out.pointlist;
557     int            *cells      = out.tetrahedronlist;
558 
559     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
560     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
561     if (label) {ierr = DMCreateLabel(*dm, labelName); ierr = DMGetLabel(*dm, labelName, &glabel);}
562     /* Set labels */
563     for (v = 0; v < numVertices; ++v) {
564       if (out.pointmarkerlist[v]) {
565         if (glabel) {ierr = DMLabelSetValue(glabel, v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);}
566       }
567     }
568     if (interpolate) {
569 #if 0
570       PetscInt e;
571 
572       /* This check is never actually executed for ctetgen (which never returns edgemarkers) and seems to be broken for
573        * tetgen */
574       for (e = 0; e < out.numberofedges; e++) {
575         if (out.edgemarkerlist[e]) {
576           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
577           const PetscInt *edges;
578           PetscInt        numEdges;
579 
580           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
581           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
582           if (glabel) {ierr = DMLabelSetValue(glabel, edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);}
583           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
584         }
585       }
586 #endif
587       for (f = 0; f < out.numberoftrifaces; f++) {
588         if (out.trifacemarkerlist[f]) {
589           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
590           const PetscInt *faces;
591           PetscInt        numFaces;
592 
593           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
594           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
595           if (glabel) {ierr = DMLabelSetValue(glabel, faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);}
596           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
597         }
598       }
599     }
600     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
601   }
602   PetscFunctionReturn(0);
603 }
604 
605 static PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
606 {
607   MPI_Comm       comm;
608   const PetscInt dim       = 3;
609   const char    *labelName = "marker";
610   ::tetgenio     in;
611   ::tetgenio     out;
612   DMLabel        label;
613   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
614   PetscMPIInt    rank;
615   PetscErrorCode ierr;
616 
617   PetscFunctionBegin;
618   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
619   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
620   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
621   ierr = MPIU_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
622   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
623   ierr = DMGetLabel(dm, labelName, &label);CHKERRQ(ierr);
624 
625   in.numberofpoints = vEnd - vStart;
626   if (in.numberofpoints > 0) {
627     PetscSection coordSection;
628     Vec          coordinates;
629     PetscScalar *array;
630 
631     in.pointlist       = new double[in.numberofpoints*dim];
632     in.pointmarkerlist = new int[in.numberofpoints];
633 
634     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
635     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
636     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
637     for (v = vStart; v < vEnd; ++v) {
638       const PetscInt idx = v - vStart;
639       PetscInt       off, d;
640 
641       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
642       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
643       if (label) {
644         PetscInt val;
645 
646         ierr = DMLabelGetValue(label, v, &val);CHKERRQ(ierr);
647         in.pointmarkerlist[idx] = (int) val;
648       }
649     }
650     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
651   }
652   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
653 
654   in.numberofcorners       = 4;
655   in.numberoftetrahedra    = cEnd - cStart;
656   in.tetrahedronvolumelist = (double*) maxVolumes;
657   if (in.numberoftetrahedra > 0) {
658     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
659     for (c = cStart; c < cEnd; ++c) {
660       const PetscInt idx      = c - cStart;
661       PetscInt      *closure = NULL;
662       PetscInt       closureSize;
663 
664       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
665       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
666       for (v = 0; v < 4; ++v) {
667         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
668       }
669       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
670     }
671   }
672   /* TODO: Put in boundary faces with markers */
673   if (!rank) {
674     char args[32];
675 
676 #if 1
677     /* Take away 'Q' for verbose output */
678     ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr);
679 #else
680     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
681 #endif
682     ::tetrahedralize(args, &in, &out);
683   }
684   in.tetrahedronvolumelist = NULL;
685 
686   {
687     DMLabel        rlabel      = NULL;
688     const PetscInt numCorners  = 4;
689     const PetscInt numCells    = out.numberoftetrahedra;
690     const PetscInt numVertices = out.numberofpoints;
691     const double   *meshCoords = out.pointlist;
692     int            *cells      = out.tetrahedronlist;
693 
694     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
695 
696     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
697     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
698     if (label) {ierr = DMCreateLabel(*dmRefined, labelName); ierr = DMGetLabel(*dmRefined, labelName, &rlabel);}
699     /* Set labels */
700     for (v = 0; v < numVertices; ++v) {
701       if (out.pointmarkerlist[v]) {
702         if (rlabel) {ierr = DMLabelSetValue(rlabel, v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);}
703       }
704     }
705     if (interpolate) {
706       PetscInt f;
707 #if 0
708       PetscInt e;
709 
710       for (e = 0; e < out.numberofedges; e++) {
711         if (out.edgemarkerlist[e]) {
712           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
713           const PetscInt *edges;
714           PetscInt        numEdges;
715 
716           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
717           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
718           if (rlabel) {ierr = DMLabelSetValue(rlabel, edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);}
719           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
720         }
721       }
722 #endif
723       for (f = 0; f < out.numberoftrifaces; f++) {
724         if (out.trifacemarkerlist[f]) {
725           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
726           const PetscInt *faces;
727           PetscInt        numFaces;
728 
729           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
730           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
731           if (rlabel) {ierr = DMLabelSetValue(rlabel, faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);}
732           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
733         }
734       }
735     }
736     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
737   }
738   PetscFunctionReturn(0);
739 }
740 #endif /* PETSC_HAVE_TETGEN */
741 
742 #if defined(PETSC_HAVE_CTETGEN)
743 #include <ctetgen.h>
744 
745 static PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
746 {
747   MPI_Comm       comm;
748   const PetscInt dim       = 3;
749   const char    *labelName = "marker";
750   PLC           *in, *out;
751   DMLabel        label;
752   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
753   PetscMPIInt    rank;
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
758   ierr = PetscOptionsGetInt(NULL,((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
759   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
760   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
761   ierr = DMGetLabel(boundary, labelName, &label);CHKERRQ(ierr);
762   ierr = PLCCreate(&in);CHKERRQ(ierr);
763   ierr = PLCCreate(&out);CHKERRQ(ierr);
764 
765   in->numberofpoints = vEnd - vStart;
766   if (in->numberofpoints > 0) {
767     PetscSection coordSection;
768     Vec          coordinates;
769     PetscScalar *array;
770 
771     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
772     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
773     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
774     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
775     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
776     for (v = vStart; v < vEnd; ++v) {
777       const PetscInt idx = v - vStart;
778       PetscInt       off, d, m = -1;
779 
780       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
781       for (d = 0; d < dim; ++d) {
782         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
783       }
784       if (label) {ierr = DMLabelGetValue(label, v, &m);CHKERRQ(ierr);}
785 
786       in->pointmarkerlist[idx] = (int) m;
787     }
788     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
789   }
790   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
791 
792   in->numberoffacets = fEnd - fStart;
793   if (in->numberoffacets > 0) {
794     ierr = PetscMalloc1(in->numberoffacets, &in->facetlist);CHKERRQ(ierr);
795     ierr = PetscMalloc1(in->numberoffacets,   &in->facetmarkerlist);CHKERRQ(ierr);
796     for (f = fStart; f < fEnd; ++f) {
797       const PetscInt idx     = f - fStart;
798       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m = -1;
799       polygon       *poly;
800 
801       in->facetlist[idx].numberofpolygons = 1;
802 
803       ierr = PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
804 
805       in->facetlist[idx].numberofholes    = 0;
806       in->facetlist[idx].holelist         = NULL;
807 
808       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
809       for (p = 0; p < numPoints*2; p += 2) {
810         const PetscInt point = points[p];
811         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
812       }
813 
814       poly                   = in->facetlist[idx].polygonlist;
815       poly->numberofvertices = numVertices;
816       ierr                   = PetscMalloc1(poly->numberofvertices, &poly->vertexlist);CHKERRQ(ierr);
817       for (v = 0; v < numVertices; ++v) {
818         const PetscInt vIdx = points[v] - vStart;
819         poly->vertexlist[v] = vIdx;
820       }
821       if (label) {ierr = DMLabelGetValue(label, f, &m);CHKERRQ(ierr);}
822       in->facetmarkerlist[idx] = (int) m;
823       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
824     }
825   }
826   if (!rank) {
827     TetGenOpts t;
828 
829     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
830     t.in        = boundary; /* Should go away */
831     t.plc       = 1;
832     t.quality   = 1;
833     t.edgesout  = 1;
834     t.zeroindex = 1;
835     t.quiet     = 1;
836     t.verbose   = verbose;
837     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
838     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
839   }
840   {
841     DMLabel        glabel      = NULL;
842     const PetscInt numCorners  = 4;
843     const PetscInt numCells    = out->numberoftetrahedra;
844     const PetscInt numVertices = out->numberofpoints;
845     double         *meshCoords;
846     int            *cells      = out->tetrahedronlist;
847 
848     if (sizeof (PetscReal) == sizeof (double)) {
849       meshCoords = (double *) out->pointlist;
850     }
851     else {
852       PetscInt i;
853 
854       ierr = PetscMalloc1(3 * numVertices,&meshCoords);CHKERRQ(ierr);
855       for (i = 0; i < 3 * numVertices; i++) {
856         meshCoords[i] = (PetscReal) out->pointlist[i];
857       }
858     }
859 
860     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
861     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
862     if (sizeof (PetscReal) != sizeof (double)) {
863       ierr = PetscFree(meshCoords);CHKERRQ(ierr);
864     }
865     if (label) {ierr = DMCreateLabel(*dm, labelName); ierr = DMGetLabel(*dm, labelName, &glabel);}
866     /* Set labels */
867     for (v = 0; v < numVertices; ++v) {
868       if (out->pointmarkerlist[v]) {
869         if (glabel) {ierr = DMLabelSetValue(glabel, v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);}
870       }
871     }
872     if (interpolate) {
873       PetscInt e;
874 
875       for (e = 0; e < out->numberofedges; e++) {
876         if (out->edgemarkerlist[e]) {
877           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
878           const PetscInt *edges;
879           PetscInt        numEdges;
880 
881           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
882           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
883           if (glabel) {ierr = DMLabelSetValue(glabel, edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);}
884           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
885         }
886       }
887       for (f = 0; f < out->numberoftrifaces; f++) {
888         if (out->trifacemarkerlist[f]) {
889           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
890           const PetscInt *faces;
891           PetscInt        numFaces;
892 
893           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
894           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
895           if (glabel) {ierr = DMLabelSetValue(glabel, faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);}
896           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
897         }
898       }
899     }
900     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
901   }
902 
903   ierr = PLCDestroy(&in);CHKERRQ(ierr);
904   ierr = PLCDestroy(&out);CHKERRQ(ierr);
905   PetscFunctionReturn(0);
906 }
907 
908 static PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
909 {
910   MPI_Comm       comm;
911   const PetscInt dim       = 3;
912   const char    *labelName = "marker";
913   PLC           *in, *out;
914   DMLabel        label;
915   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
916   PetscMPIInt    rank;
917   PetscErrorCode ierr;
918 
919   PetscFunctionBegin;
920   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
921   ierr = PetscOptionsGetInt(NULL,((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
922   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
923   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
924   ierr = MPIU_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
925   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
926   ierr = DMGetLabel(dm, labelName, &label);CHKERRQ(ierr);
927   ierr = PLCCreate(&in);CHKERRQ(ierr);
928   ierr = PLCCreate(&out);CHKERRQ(ierr);
929 
930   in->numberofpoints = vEnd - vStart;
931   if (in->numberofpoints > 0) {
932     PetscSection coordSection;
933     Vec          coordinates;
934     PetscScalar *array;
935 
936     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
937     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
938     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
939     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
940     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
941     for (v = vStart; v < vEnd; ++v) {
942       const PetscInt idx = v - vStart;
943       PetscInt       off, d, m = -1;
944 
945       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
946       for (d = 0; d < dim; ++d) {
947         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
948       }
949       if (label) {ierr = DMLabelGetValue(label, v, &m);CHKERRQ(ierr);}
950 
951       in->pointmarkerlist[idx] = (int) m;
952     }
953     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
954   }
955   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
956 
957   in->numberofcorners       = 4;
958   in->numberoftetrahedra    = cEnd - cStart;
959   in->tetrahedronvolumelist = maxVolumes;
960   if (in->numberoftetrahedra > 0) {
961     ierr = PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);CHKERRQ(ierr);
962     for (c = cStart; c < cEnd; ++c) {
963       const PetscInt idx      = c - cStart;
964       PetscInt      *closure = NULL;
965       PetscInt       closureSize;
966 
967       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
968       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
969       for (v = 0; v < 4; ++v) {
970         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
971       }
972       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
973     }
974   }
975   if (!rank) {
976     TetGenOpts t;
977 
978     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
979 
980     t.in        = dm; /* Should go away */
981     t.refine    = 1;
982     t.varvolume = 1;
983     t.quality   = 1;
984     t.edgesout  = 1;
985     t.zeroindex = 1;
986     t.quiet     = 1;
987     t.verbose   = verbose; /* Change this */
988 
989     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
990     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
991   }
992   in->tetrahedronvolumelist = NULL;
993   {
994     DMLabel        rlabel      = NULL;
995     const PetscInt numCorners  = 4;
996     const PetscInt numCells    = out->numberoftetrahedra;
997     const PetscInt numVertices = out->numberofpoints;
998     double         *meshCoords;
999     int            *cells      = out->tetrahedronlist;
1000     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
1001 
1002     if (sizeof (PetscReal) == sizeof (double)) {
1003       meshCoords = (double *) out->pointlist;
1004     }
1005     else {
1006       PetscInt i;
1007 
1008       ierr = PetscMalloc1(3 * numVertices,&meshCoords);CHKERRQ(ierr);
1009       for (i = 0; i < 3 * numVertices; i++) {
1010         meshCoords[i] = (PetscReal) out->pointlist[i];
1011       }
1012     }
1013 
1014     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
1015     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
1016     if (sizeof (PetscReal) != sizeof (double)) {
1017       ierr = PetscFree(meshCoords);CHKERRQ(ierr);
1018     }
1019     if (label) {ierr = DMCreateLabel(*dmRefined, labelName); ierr = DMGetLabel(*dmRefined, labelName, &rlabel);}
1020     /* Set labels */
1021     for (v = 0; v < numVertices; ++v) {
1022       if (out->pointmarkerlist[v]) {
1023         if (rlabel) {ierr = DMLabelSetValue(rlabel, v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);}
1024       }
1025     }
1026     if (interpolate) {
1027       PetscInt e, f;
1028 
1029       for (e = 0; e < out->numberofedges; e++) {
1030         if (out->edgemarkerlist[e]) {
1031           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
1032           const PetscInt *edges;
1033           PetscInt        numEdges;
1034 
1035           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
1036           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
1037           if (rlabel) {ierr = DMLabelSetValue(rlabel, edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);}
1038           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
1039         }
1040       }
1041       for (f = 0; f < out->numberoftrifaces; f++) {
1042         if (out->trifacemarkerlist[f]) {
1043           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
1044           const PetscInt *faces;
1045           PetscInt        numFaces;
1046 
1047           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
1048           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
1049           if (rlabel) {ierr = DMLabelSetValue(rlabel, faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);}
1050           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
1051         }
1052       }
1053     }
1054     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
1055   }
1056   ierr = PLCDestroy(&in);CHKERRQ(ierr);
1057   ierr = PLCDestroy(&out);CHKERRQ(ierr);
1058   PetscFunctionReturn(0);
1059 }
1060 #endif /* PETSC_HAVE_CTETGEN */
1061 
1062 /*@C
1063   DMPlexGenerate - Generates a mesh.
1064 
1065   Not Collective
1066 
1067   Input Parameters:
1068 + boundary - The DMPlex boundary object
1069 . name - The mesh generation package name
1070 - interpolate - Flag to create intermediate mesh elements
1071 
1072   Output Parameter:
1073 . mesh - The DMPlex object
1074 
1075   Level: intermediate
1076 
1077 .keywords: mesh, elements
1078 .seealso: DMPlexCreate(), DMRefine()
1079 @*/
1080 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
1081 {
1082   PetscInt       dim;
1083   char           genname[1024];
1084   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
1085   PetscErrorCode ierr;
1086 
1087   PetscFunctionBegin;
1088   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
1089   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
1090   ierr = DMGetDimension(boundary, &dim);CHKERRQ(ierr);
1091   ierr = PetscOptionsGetString(((PetscObject) boundary)->options,((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
1092   if (flg) name = genname;
1093   if (name) {
1094     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
1095     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
1096     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
1097   }
1098   switch (dim) {
1099   case 1:
1100     if (!name || isTriangle) {
1101 #if defined(PETSC_HAVE_TRIANGLE)
1102       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
1103 #else
1104       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
1105 #endif
1106     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
1107     break;
1108   case 2:
1109     if (!name) {
1110 #if defined(PETSC_HAVE_CTETGEN)
1111       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
1112 #elif defined(PETSC_HAVE_TETGEN)
1113       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
1114 #else
1115       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "External package CTetgen or Tetgen needed.\nPlease reconfigure with '--download-ctetgen' or '--with-clanguage=cxx --download-tetgen'.");
1116 #endif
1117     } else if (isCTetgen) {
1118 #if defined(PETSC_HAVE_CTETGEN)
1119       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
1120 #else
1121       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
1122 #endif
1123     } else if (isTetgen) {
1124 #if defined(PETSC_HAVE_TETGEN)
1125       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
1126 #else
1127       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --download-tetgen.");
1128 #endif
1129     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
1130     break;
1131   default:
1132     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
1133   }
1134   PetscFunctionReturn(0);
1135 }
1136 
1137 static PetscErrorCode DMRefine_Plex_Label(DM dm, DMLabel adaptLabel, PetscInt cStart, PetscInt cEnd, PetscReal maxVolumes[])
1138 {
1139   PetscInt       dim, c;
1140   PetscReal      refRatio;
1141   PetscErrorCode ierr;
1142 
1143   PetscFunctionBegin;
1144   ierr     = DMGetDimension(dm,&dim);CHKERRQ(ierr);
1145   refRatio = (PetscReal) ((PetscInt) 1 << dim);
1146   for (c = cStart; c < cEnd; c++) {
1147     PetscReal vol;
1148     PetscInt  i, closureSize = 0;
1149     PetscInt  *closure = NULL;
1150     PetscBool anyRefine  = PETSC_FALSE;
1151     PetscBool anyCoarsen = PETSC_FALSE;
1152     PetscBool anyKeep    = PETSC_FALSE;
1153 
1154     ierr = DMPlexComputeCellGeometryFVM(dm,c,&vol,NULL,NULL);CHKERRQ(ierr);
1155     maxVolumes[c - cStart] = vol;
1156     ierr = DMPlexGetTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1157     for (i = 0; i < closureSize; i++) {
1158       PetscInt point = closure[2 * i], refFlag;
1159 
1160       ierr = DMLabelGetValue(adaptLabel,point,&refFlag);CHKERRQ(ierr);
1161       switch (refFlag) {
1162       case DM_ADAPT_REFINE:
1163         anyRefine = PETSC_TRUE;
1164         break;
1165       case DM_ADAPT_COARSEN:
1166         anyCoarsen = PETSC_TRUE;
1167         break;
1168       case DM_ADAPT_KEEP:
1169         anyKeep = PETSC_TRUE;
1170         break;
1171       case DM_ADAPT_DETERMINE:
1172         break;
1173       default:
1174         SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlex does not support refinement flag %D\n",refFlag);
1175         break;
1176       }
1177       if (anyRefine) break;
1178     }
1179     ierr = DMPlexRestoreTransitiveClosure(dm,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1180     if (anyRefine) {
1181       maxVolumes[c - cStart] = vol / refRatio;
1182     } else if (anyKeep) {
1183       maxVolumes[c - cStart] = vol;
1184     } else if (anyCoarsen) {
1185       maxVolumes[c - cStart] = vol * refRatio;
1186     }
1187   }
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 static PetscErrorCode DMRefine_Plex_Internal(DM dm, MPI_Comm comm, DMLabel adaptLabel, DM *dmRefined)
1192 {
1193   PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *);
1194   PetscReal        refinementLimit;
1195   PetscInt         dim, cStart, cEnd;
1196   char             genname[1024], *name = NULL;
1197   PetscBool        isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg, localized;
1198   PetscErrorCode   ierr;
1199 
1200   PetscFunctionBegin;
1201   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1202   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
1203   if (isUniform) {
1204     CellRefiner cellRefiner;
1205 
1206     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
1207     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
1208     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
1209     if (localized) {
1210       ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);
1211     }
1212     PetscFunctionReturn(0);
1213   }
1214   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
1215   ierr = DMPlexGetRefinementFunction(dm, &refinementFunc);CHKERRQ(ierr);
1216   if (refinementLimit == 0.0 && !refinementFunc) PetscFunctionReturn(0);
1217   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1218   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1219   ierr = PetscOptionsGetString(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
1220   if (flg) name = genname;
1221   if (name) {
1222     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
1223     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
1224     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
1225   }
1226   switch (dim) {
1227   case 2:
1228     if (!name || isTriangle) {
1229 #if defined(PETSC_HAVE_TRIANGLE)
1230       PetscReal *maxVolumes;
1231       PetscInt  c;
1232 
1233       ierr = PetscMalloc1(cEnd - cStart, &maxVolumes);CHKERRQ(ierr);
1234       if (adaptLabel) {
1235         ierr = DMRefine_Plex_Label(dm,adaptLabel,cStart,cEnd,maxVolumes);CHKERRQ(ierr);
1236       } else if (refinementFunc) {
1237         for (c = cStart; c < cEnd; ++c) {
1238           PetscReal vol, centroid[3];
1239           PetscReal maxVol;
1240 
1241           ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, centroid, NULL);CHKERRQ(ierr);
1242           ierr = (*refinementFunc)(centroid, &maxVol);CHKERRQ(ierr);
1243           maxVolumes[c - cStart] = (double) maxVol;
1244         }
1245       } else {
1246         for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
1247       }
1248 #if !defined(PETSC_USE_REAL_DOUBLE)
1249       {
1250         double *mvols;
1251         ierr = PetscMalloc1(cEnd - cStart,&mvols);CHKERRQ(ierr);
1252         for (c = 0; c < cEnd-cStart; ++c) mvols[c] = (double)maxVolumes[c];
1253         ierr = DMPlexRefine_Triangle(dm, mvols, dmRefined);CHKERRQ(ierr);
1254         ierr = PetscFree(mvols);CHKERRQ(ierr);
1255       }
1256 #else
1257       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
1258 #endif
1259       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
1260 #else
1261       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
1262 #endif
1263     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
1264     break;
1265   case 3:
1266     if (!name || isCTetgen || isTetgen) {
1267       PetscReal *maxVolumes;
1268       PetscInt   c;
1269 
1270       ierr = PetscMalloc1(cEnd - cStart, &maxVolumes);CHKERRQ(ierr);
1271       if (adaptLabel) {
1272         ierr = DMRefine_Plex_Label(dm,adaptLabel,cStart,cEnd,maxVolumes);CHKERRQ(ierr);
1273       } else if (refinementFunc) {
1274         for (c = cStart; c < cEnd; ++c) {
1275           PetscReal vol, centroid[3];
1276 
1277           ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, centroid, NULL);CHKERRQ(ierr);
1278           ierr = (*refinementFunc)(centroid, &maxVolumes[c-cStart]);CHKERRQ(ierr);
1279         }
1280       } else {
1281         for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
1282       }
1283       if (!name) {
1284 #if defined(PETSC_HAVE_CTETGEN)
1285         ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
1286 #elif defined(PETSC_HAVE_TETGEN)
1287         ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
1288 #else
1289         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "External package CTetgen or Tetgen needed.\nPlease reconfigure with '--download-ctetgen' or '--with-clanguage=cxx --download-tetgen'.");
1290 #endif
1291       } else if (isCTetgen) {
1292 #if defined(PETSC_HAVE_CTETGEN)
1293         ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
1294 #else
1295         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
1296 #endif
1297       } else {
1298 #if defined(PETSC_HAVE_TETGEN)
1299         ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
1300 #else
1301         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --download-tetgen.");
1302 #endif
1303       }
1304       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
1305     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
1306     break;
1307   default:
1308     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
1309   }
1310   ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
1311   if (localized) {
1312     ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);
1313   }
1314   PetscFunctionReturn(0);
1315 }
1316 
1317 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
1318 {
1319   PetscErrorCode ierr;
1320 
1321   PetscFunctionBegin;
1322   ierr = DMRefine_Plex_Internal(dm,comm,NULL,dmRefined);CHKERRQ(ierr);
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 PetscErrorCode DMAdaptLabel_Plex(DM dm, DMLabel adaptLabel, DM *dmAdapted)
1327 {
1328   PetscInt       defFlag, minFlag, maxFlag, numFlags, i;
1329   const PetscInt *flags;
1330   IS             flagIS;
1331   PetscErrorCode ierr;
1332 
1333   PetscFunctionBegin;
1334   ierr = DMLabelGetDefaultValue(adaptLabel,&defFlag);CHKERRQ(ierr);
1335   minFlag = defFlag;
1336   maxFlag = defFlag;
1337   ierr = DMLabelGetValueIS(adaptLabel,&flagIS);CHKERRQ(ierr);
1338   ierr = ISGetLocalSize(flagIS,&numFlags);CHKERRQ(ierr);
1339   ierr = ISGetIndices(flagIS,&flags);CHKERRQ(ierr);
1340   for (i = 0; i < numFlags; i++) {
1341     PetscInt flag = flags[i];
1342 
1343     minFlag = PetscMin(minFlag,flag);
1344     maxFlag = PetscMax(maxFlag,flag);
1345   }
1346   ierr = ISRestoreIndices(flagIS,&flags);CHKERRQ(ierr);
1347   ierr = ISDestroy(&flagIS);CHKERRQ(ierr);
1348   {
1349     PetscInt minMaxFlag[2], minMaxFlagGlobal[2];
1350 
1351     minMaxFlag[0] = minFlag;
1352     minMaxFlag[1] = -maxFlag;
1353     ierr = MPI_Allreduce(minMaxFlag,minMaxFlagGlobal,2,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1354     minFlag = minMaxFlagGlobal[0];
1355     maxFlag = -minMaxFlagGlobal[1];
1356   }
1357   if (minFlag == maxFlag) {
1358     switch (minFlag) {
1359     case DM_ADAPT_DETERMINE:
1360       *dmAdapted = NULL;
1361       break;
1362     case DM_ADAPT_REFINE:
1363       ierr = DMPlexSetRefinementUniform(dm,PETSC_TRUE);CHKERRQ(ierr);
1364       ierr = DMRefine(dm,MPI_COMM_NULL,dmAdapted);CHKERRQ(ierr);
1365       break;
1366     case DM_ADAPT_COARSEN:
1367       ierr = DMCoarsen(dm,MPI_COMM_NULL,dmAdapted);CHKERRQ(ierr);
1368       break;
1369     default:
1370       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"DMPlex does not support refinement flag %D\n",minFlag);
1371       break;
1372     }
1373   } else {
1374     ierr = DMPlexSetRefinementUniform(dm,PETSC_FALSE);CHKERRQ(ierr);
1375     ierr = DMRefine_Plex_Internal(dm,MPI_COMM_NULL,adaptLabel,dmAdapted);CHKERRQ(ierr);
1376   }
1377   PetscFunctionReturn(0);
1378 }
1379 
1380 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
1381 {
1382   DM             cdm = dm;
1383   PetscInt       r;
1384   PetscBool      isUniform, localized;
1385   PetscErrorCode ierr;
1386 
1387   PetscFunctionBegin;
1388   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
1389   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1390   if (!isUniform) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Non-uniform refinement is incompatible with the hierarchy");
1391   for (r = 0; r < nlevels; ++r) {
1392     CellRefiner cellRefiner;
1393 
1394     ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
1395     ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
1396     ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
1397     if (localized) {
1398       ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);
1399     }
1400     ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
1401     ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
1402     cdm  = dmRefined[r];
1403   }
1404   PetscFunctionReturn(0);
1405 }
1406