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