xref: /petsc/src/dm/impls/plex/plex.c (revision fcdd1374ba1eef48d14a15804db8ae436b941944)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/isimpl.h>
4 #include <petscsf.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM;
8 
9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer);
12 
13 #undef __FUNCT__
14 #define __FUNCT__ "DMPlexGetFieldType_Internal"
15 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
16 {
17   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, vdof = 0, cdof = 0;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   *ft  = PETSC_VTK_POINT_FIELD;
22   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
23   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
24   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
25   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
26   if (field >= 0) {
27     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vdof);CHKERRQ(ierr);}
28     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &cdof);CHKERRQ(ierr);}
29   } else {
30     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
31     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
32   }
33   if (vdof) {
34     *sStart = vStart;
35     *sEnd   = vEnd;
36     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
37     else             *ft = PETSC_VTK_POINT_FIELD;
38   } else if (cdof) {
39     *sStart = cStart;
40     *sEnd   = cEnd;
41     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
42     else             *ft = PETSC_VTK_CELL_FIELD;
43   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
44   PetscFunctionReturn(0);
45 }
46 
47 #undef __FUNCT__
48 #define __FUNCT__ "VecView_Plex_Local"
49 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
50 {
51   DM             dm;
52   PetscBool      isvtk, ishdf5, isseq;
53   PetscErrorCode ierr;
54 
55   PetscFunctionBegin;
56   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
57   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
58   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
59   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
60   ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
61   if (isvtk || ishdf5) {
62     PetscInt  numFields;
63     PetscBool fem = PETSC_FALSE;
64 
65     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
66     if (numFields) {
67       PetscObject fe;
68 
69       ierr = DMGetField(dm, 0, &fe);CHKERRQ(ierr);
70       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
71     }
72     if (fem) {
73       ierr = DMPlexInsertBoundaryValuesFEM(dm, v);CHKERRQ(ierr);
74     } else {
75       PetscObject faceGeometry;
76 
77       /* TODO Fix the time, and add FVM objects */
78       ierr = PetscObjectQuery((PetscObject) dm, "FaceGeometry", &faceGeometry);CHKERRQ(ierr);
79       if (faceGeometry) {ierr = DMPlexInsertBoundaryValuesFVM(dm, 0.0, v);CHKERRQ(ierr);}
80     }
81   }
82   if (isvtk) {
83     PetscSection            section;
84     PetscViewerVTKFieldType ft;
85     PetscInt                pStart, pEnd;
86 
87     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
88     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
89     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
90     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
91     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
92   } else if (ishdf5) {
93 #if defined(PETSC_HAVE_HDF5)
94     ierr = VecView_Plex_Local_HDF5(v, viewer);CHKERRQ(ierr);
95 #else
96     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
97 #endif
98   } else {
99     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
100     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
101   }
102   PetscFunctionReturn(0);
103 }
104 
105 #undef __FUNCT__
106 #define __FUNCT__ "VecView_Plex"
107 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
108 {
109   DM             dm;
110   PetscBool      isvtk, ishdf5, isseq;
111   PetscErrorCode ierr;
112 
113   PetscFunctionBegin;
114   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
115   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
116   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
117   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
118   ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
119   if (isvtk) {
120     Vec         locv;
121     const char *name;
122 
123     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
124     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
125     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
126     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
127     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
128     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
129     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
130   } else if (ishdf5) {
131 #if defined(PETSC_HAVE_HDF5)
132     ierr = VecView_Plex_HDF5(v, viewer);CHKERRQ(ierr);
133 #else
134     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
135 #endif
136   } else {
137     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
138     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
139   }
140   PetscFunctionReturn(0);
141 }
142 
143 #undef __FUNCT__
144 #define __FUNCT__ "VecLoad_Plex_Local"
145 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
146 {
147   DM             dm;
148   PetscBool      ishdf5;
149   PetscErrorCode ierr;
150 
151   PetscFunctionBegin;
152   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
153   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
154   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
155   if (ishdf5) {
156     DM          dmBC;
157     Vec         gv;
158     const char *name;
159 
160     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
161     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
162     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
163     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
164     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
165     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
166     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
167     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
168   } else {
169     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
170   }
171   PetscFunctionReturn(0);
172 }
173 
174 #undef __FUNCT__
175 #define __FUNCT__ "VecLoad_Plex"
176 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
177 {
178   DM             dm;
179   PetscBool      ishdf5;
180   PetscErrorCode ierr;
181 
182   PetscFunctionBegin;
183   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
184   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
185   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
186   if (ishdf5) {
187 #if defined(PETSC_HAVE_HDF5)
188     ierr = VecLoad_Plex_HDF5(v, viewer);CHKERRQ(ierr);
189 #else
190     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
191 #endif
192   } else {
193     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
194   }
195   PetscFunctionReturn(0);
196 }
197 
198 #undef __FUNCT__
199 #define __FUNCT__ "DMPlexView_Ascii"
200 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
201 {
202   DM_Plex          *mesh = (DM_Plex*) dm->data;
203   DM                cdm;
204   DMLabel           markers;
205   PetscSection      coordSection;
206   Vec               coordinates;
207   PetscViewerFormat format;
208   PetscErrorCode    ierr;
209 
210   PetscFunctionBegin;
211   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
212   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
213   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
214   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
215   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
216     const char *name;
217     PetscInt    maxConeSize, maxSupportSize;
218     PetscInt    pStart, pEnd, p;
219     PetscMPIInt rank, size;
220 
221     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
222     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
223     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
224     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
225     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
226     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
227     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
228     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
230     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
231     for (p = pStart; p < pEnd; ++p) {
232       PetscInt dof, off, s;
233 
234       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
235       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
236       for (s = off; s < off+dof; ++s) {
237         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
238       }
239     }
240     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
241     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
242     for (p = pStart; p < pEnd; ++p) {
243       PetscInt dof, off, c;
244 
245       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
246       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
247       for (c = off; c < off+dof; ++c) {
248         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
249       }
250     }
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
253     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
254     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
255     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
256     if (size > 1) {
257       PetscSF sf;
258 
259       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
260       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
261     }
262     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
263   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
264     const char  *name;
265     const char  *colors[3] = {"red", "blue", "green"};
266     const int    numColors  = 3;
267     PetscReal    scale      = 2.0;
268     PetscScalar *coords;
269     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
270     PetscMPIInt  rank, size;
271 
272     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
273     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
274     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
275     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
276     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
277     ierr = PetscViewerASCIIPrintf(viewer, "\
278 \\documentclass[crop,multi=false]{standalone}\n\n\
279 \\usepackage{tikz}\n\
280 \\usepackage{pgflibraryshapes}\n\
281 \\usetikzlibrary{backgrounds}\n\
282 \\usetikzlibrary{arrows}\n\
283 \\begin{document}\n\
284 \\section{%s}\n\
285 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
287     for (p = 0; p < size; ++p) {
288       if (p > 0 && p == size-1) {
289         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
290       } else if (p > 0) {
291         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
292       }
293       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
294     }
295     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
296 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
297     /* Plot vertices */
298     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
299     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
300     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
301     for (v = vStart; v < vEnd; ++v) {
302       PetscInt off, dof, d;
303 
304       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
305       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
306       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
307       for (d = 0; d < dof; ++d) {
308         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
309         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*PetscRealPart(coords[off+d])));CHKERRQ(ierr);
310       }
311       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
312     }
313     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
314     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
315     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
316     /* Plot edges */
317     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
318     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
319     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
320     for (e = eStart; e < eEnd; ++e) {
321       const PetscInt *cone;
322       PetscInt        coneSize, offA, offB, dof, d;
323 
324       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
325       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
326       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
327       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
328       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
329       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
330       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
331       for (d = 0; d < dof; ++d) {
332         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
333         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d])));CHKERRQ(ierr);
334       }
335       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
336     }
337     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
338     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
339     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
340     /* Plot cells */
341     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
342     for (c = cStart; c < cEnd; ++c) {
343       PetscInt *closure = NULL;
344       PetscInt  closureSize, firstPoint = -1;
345 
346       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
347       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
348       for (p = 0; p < closureSize*2; p += 2) {
349         const PetscInt point = closure[p];
350 
351         if ((point < vStart) || (point >= vEnd)) continue;
352         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
353         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
354         if (firstPoint < 0) firstPoint = point;
355       }
356       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
357       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
358       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
359     }
360     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
361     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
362     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
363   } else {
364     MPI_Comm    comm;
365     PetscInt   *sizes, *hybsizes;
366     PetscInt    locDepth, depth, dim, d, pMax[4];
367     PetscInt    pStart, pEnd, p;
368     PetscInt    numLabels, l;
369     const char *name;
370     PetscMPIInt size;
371 
372     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
373     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
374     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
375     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
376     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);CHKERRQ(ierr);}
377     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);}
378     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
379     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
380     ierr = DMPlexGetHybridBounds(dm, &pMax[depth], &pMax[depth-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
381     ierr = PetscMalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr);
382     if (depth == 1) {
383       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
384       pEnd = pEnd - pStart;
385       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
386       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
387       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
388       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
389       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
390       pEnd = pEnd - pStart;
391       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
392       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
393       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
394       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
395     } else {
396       for (d = 0; d <= dim; d++) {
397         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
398         pEnd    -= pStart;
399         pMax[d] -= pStart;
400         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
401         ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
402         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
403         for (p = 0; p < size; ++p) {
404           if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
405           else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
406         }
407         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
408       }
409     }
410     ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr);
411     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
412     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
413     for (l = 0; l < numLabels; ++l) {
414       DMLabel         label;
415       const char     *name;
416       IS              valueIS;
417       const PetscInt *values;
418       PetscInt        numValues, v;
419 
420       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
421       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
422       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
423       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
424       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
425       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
426       for (v = 0; v < numValues; ++v) {
427         PetscInt size;
428 
429         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
430         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
431         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
432       }
433       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
434       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
435       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
436     }
437   }
438   PetscFunctionReturn(0);
439 }
440 
441 #undef __FUNCT__
442 #define __FUNCT__ "DMView_Plex"
443 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
444 {
445   PetscBool      iascii, ishdf5;
446   PetscErrorCode ierr;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
451   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
452   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
453   if (iascii) {
454     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
455   } else if (ishdf5) {
456 #if defined(PETSC_HAVE_HDF5)
457     ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);CHKERRQ(ierr);
458     ierr = DMPlexView_HDF5(dm, viewer);CHKERRQ(ierr);
459     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
460 #else
461     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
462 #endif
463   }
464   PetscFunctionReturn(0);
465 }
466 
467 #undef __FUNCT__
468 #define __FUNCT__ "DMLoad_Plex"
469 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
470 {
471   PetscBool      isbinary, ishdf5;
472   PetscErrorCode ierr;
473 
474   PetscFunctionBegin;
475   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
476   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
477   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
478   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
479   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
480   else if (ishdf5) {
481 #if defined(PETSC_HAVE_HDF5)
482     DM odm;
483     ierr = DMCreate(PetscObjectComm((PetscObject) dm), &odm);CHKERRQ(ierr);
484     ierr = DMSetType(odm, DMPLEX);CHKERRQ(ierr);
485     ierr = DMPlexLoad_HDF5(odm, viewer);CHKERRQ(ierr);
486     ierr = DMPlexInterpolate(odm, &dm);CHKERRQ(ierr);
487     ierr = DMPlexCopyCoordinates(odm, dm);CHKERRQ(ierr);
488     ierr = DMPlexCopyLabels(odm, dm);CHKERRQ(ierr);
489     ierr = DMDestroy(&odm);CHKERRQ(ierr);
490 #else
491     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
492 #endif
493   }
494   PetscFunctionReturn(0);
495 }
496 
497 #undef __FUNCT__
498 #define __FUNCT__ "BoundaryDestroy"
499 static PetscErrorCode BoundaryDestroy(DMBoundary *boundary)
500 {
501   DMBoundary     b, next;
502   PetscErrorCode ierr;
503 
504   PetscFunctionBeginUser;
505   if (!boundary) PetscFunctionReturn(0);
506   b = *boundary;
507   *boundary = NULL;
508   for (; b; b = next) {
509     next = b->next;
510     ierr = PetscFree(b->ids);CHKERRQ(ierr);
511     ierr = PetscFree(b->name);CHKERRQ(ierr);
512     ierr = PetscFree(b);CHKERRQ(ierr);
513   }
514   PetscFunctionReturn(0);
515 }
516 
517 #undef __FUNCT__
518 #define __FUNCT__ "DMDestroy_Plex"
519 PetscErrorCode DMDestroy_Plex(DM dm)
520 {
521   DM_Plex       *mesh = (DM_Plex*) dm->data;
522   DMLabel        next  = mesh->labels;
523   PetscErrorCode ierr;
524 
525   PetscFunctionBegin;
526   if (--mesh->refct > 0) PetscFunctionReturn(0);
527   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
528   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
529   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
530   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
531   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
532   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
533   while (next) {
534     DMLabel tmp = next->next;
535 
536     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
537     next = tmp;
538   }
539   ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr);
540   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
541   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
542   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
543   ierr = BoundaryDestroy(&mesh->boundary);CHKERRQ(ierr);
544   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
545   ierr = PetscFree(mesh);CHKERRQ(ierr);
546   PetscFunctionReturn(0);
547 }
548 
549 #undef __FUNCT__
550 #define __FUNCT__ "DMCreateMatrix_Plex"
551 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
552 {
553   PetscSection   section, sectionGlobal;
554   PetscInt       bs = -1;
555   PetscInt       localSize;
556   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
557   PetscErrorCode ierr;
558   MatType        mtype;
559 
560   PetscFunctionBegin;
561   ierr = MatInitializePackage();CHKERRQ(ierr);
562   mtype = dm->mattype;
563   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
564   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
565   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
566   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
567   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
568   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
569   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
570   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
571   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
572   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
573   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
574   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
575   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
576   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
577   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
578   if (!isShell) {
579     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
580     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
581 
582     if (bs < 0) {
583       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
584         PetscInt pStart, pEnd, p, dof, cdof;
585 
586         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
587         for (p = pStart; p < pEnd; ++p) {
588           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
589           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
590           if (dof-cdof) {
591             if (bs < 0) {
592               bs = dof-cdof;
593             } else if (bs != dof-cdof) {
594               /* Layout does not admit a pointwise block size */
595               bs = 1;
596               break;
597             }
598           }
599         }
600         /* Must have same blocksize on all procs (some might have no points) */
601         bsLocal = bs;
602         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
603         bsLocal = bs < 0 ? bsMax : bs;
604         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
605         if (bsMin != bsMax) {
606           bs = 1;
607         } else {
608           bs = bsMax;
609         }
610       } else {
611         bs = 1;
612       }
613     }
614     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
615     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
616     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
617   }
618   PetscFunctionReturn(0);
619 }
620 
621 #undef __FUNCT__
622 #define __FUNCT__ "DMPlexGetDimension"
623 /*@
624   DMPlexGetDimension - Return the topological mesh dimension
625 
626   Not collective
627 
628   Input Parameter:
629 . mesh - The DMPlex
630 
631   Output Parameter:
632 . dim - The topological mesh dimension
633 
634   Level: beginner
635 
636 .seealso: DMPlexCreate()
637 @*/
638 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
639 {
640   DM_Plex *mesh = (DM_Plex*) dm->data;
641 
642   PetscFunctionBegin;
643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
644   PetscValidPointer(dim, 2);
645   *dim = mesh->dim;
646   PetscFunctionReturn(0);
647 }
648 
649 #undef __FUNCT__
650 #define __FUNCT__ "DMPlexSetDimension"
651 /*@
652   DMPlexSetDimension - Set the topological mesh dimension
653 
654   Collective on mesh
655 
656   Input Parameters:
657 + mesh - The DMPlex
658 - dim - The topological mesh dimension
659 
660   Level: beginner
661 
662 .seealso: DMPlexCreate()
663 @*/
664 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
665 {
666   DM_Plex *mesh = (DM_Plex*) dm->data;
667 
668   PetscFunctionBegin;
669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
670   PetscValidLogicalCollectiveInt(dm, dim, 2);
671   mesh->dim = dim;
672   PetscFunctionReturn(0);
673 }
674 
675 #undef __FUNCT__
676 #define __FUNCT__ "DMPlexGetChart"
677 /*@
678   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
679 
680   Not collective
681 
682   Input Parameter:
683 . mesh - The DMPlex
684 
685   Output Parameters:
686 + pStart - The first mesh point
687 - pEnd   - The upper bound for mesh points
688 
689   Level: beginner
690 
691 .seealso: DMPlexCreate(), DMPlexSetChart()
692 @*/
693 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
694 {
695   DM_Plex       *mesh = (DM_Plex*) dm->data;
696   PetscErrorCode ierr;
697 
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
700   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
701   PetscFunctionReturn(0);
702 }
703 
704 #undef __FUNCT__
705 #define __FUNCT__ "DMPlexSetChart"
706 /*@
707   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
708 
709   Not collective
710 
711   Input Parameters:
712 + mesh - The DMPlex
713 . pStart - The first mesh point
714 - pEnd   - The upper bound for mesh points
715 
716   Output Parameters:
717 
718   Level: beginner
719 
720 .seealso: DMPlexCreate(), DMPlexGetChart()
721 @*/
722 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
723 {
724   DM_Plex       *mesh = (DM_Plex*) dm->data;
725   PetscErrorCode ierr;
726 
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
729   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
730   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
731   PetscFunctionReturn(0);
732 }
733 
734 #undef __FUNCT__
735 #define __FUNCT__ "DMPlexGetConeSize"
736 /*@
737   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
738 
739   Not collective
740 
741   Input Parameters:
742 + mesh - The DMPlex
743 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
744 
745   Output Parameter:
746 . size - The cone size for point p
747 
748   Level: beginner
749 
750 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
751 @*/
752 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
753 {
754   DM_Plex       *mesh = (DM_Plex*) dm->data;
755   PetscErrorCode ierr;
756 
757   PetscFunctionBegin;
758   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
759   PetscValidPointer(size, 3);
760   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
761   PetscFunctionReturn(0);
762 }
763 
764 #undef __FUNCT__
765 #define __FUNCT__ "DMPlexSetConeSize"
766 /*@
767   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
768 
769   Not collective
770 
771   Input Parameters:
772 + mesh - The DMPlex
773 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
774 - size - The cone size for point p
775 
776   Output Parameter:
777 
778   Note:
779   This should be called after DMPlexSetChart().
780 
781   Level: beginner
782 
783 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
784 @*/
785 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
786 {
787   DM_Plex       *mesh = (DM_Plex*) dm->data;
788   PetscErrorCode ierr;
789 
790   PetscFunctionBegin;
791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
792   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
793 
794   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
795   PetscFunctionReturn(0);
796 }
797 
798 #undef __FUNCT__
799 #define __FUNCT__ "DMPlexGetCone"
800 /*@C
801   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
802 
803   Not collective
804 
805   Input Parameters:
806 + mesh - The DMPlex
807 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
808 
809   Output Parameter:
810 . cone - An array of points which are on the in-edges for point p
811 
812   Level: beginner
813 
814   Fortran Notes:
815   Since it returns an array, this routine is only available in Fortran 90, and you must
816   include petsc.h90 in your code.
817 
818   You must also call DMPlexRestoreCone() after you finish using the returned array.
819 
820 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
821 @*/
822 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
823 {
824   DM_Plex       *mesh = (DM_Plex*) dm->data;
825   PetscInt       off;
826   PetscErrorCode ierr;
827 
828   PetscFunctionBegin;
829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
830   PetscValidPointer(cone, 3);
831   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
832   *cone = &mesh->cones[off];
833   PetscFunctionReturn(0);
834 }
835 
836 #undef __FUNCT__
837 #define __FUNCT__ "DMPlexSetCone"
838 /*@
839   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
840 
841   Not collective
842 
843   Input Parameters:
844 + mesh - The DMPlex
845 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
846 - cone - An array of points which are on the in-edges for point p
847 
848   Output Parameter:
849 
850   Note:
851   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
852 
853   Level: beginner
854 
855 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
856 @*/
857 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
858 {
859   DM_Plex       *mesh = (DM_Plex*) dm->data;
860   PetscInt       pStart, pEnd;
861   PetscInt       dof, off, c;
862   PetscErrorCode ierr;
863 
864   PetscFunctionBegin;
865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
866   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
867   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
868   if (dof) PetscValidPointer(cone, 3);
869   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
870   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
871   for (c = 0; c < dof; ++c) {
872     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
873     mesh->cones[off+c] = cone[c];
874   }
875   PetscFunctionReturn(0);
876 }
877 
878 #undef __FUNCT__
879 #define __FUNCT__ "DMPlexGetConeOrientation"
880 /*@C
881   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
882 
883   Not collective
884 
885   Input Parameters:
886 + mesh - The DMPlex
887 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
888 
889   Output Parameter:
890 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
891                     integer giving the prescription for cone traversal. If it is negative, the cone is
892                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
893                     the index of the cone point on which to start.
894 
895   Level: beginner
896 
897   Fortran Notes:
898   Since it returns an array, this routine is only available in Fortran 90, and you must
899   include petsc.h90 in your code.
900 
901   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
902 
903 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
904 @*/
905 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
906 {
907   DM_Plex       *mesh = (DM_Plex*) dm->data;
908   PetscInt       off;
909   PetscErrorCode ierr;
910 
911   PetscFunctionBegin;
912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
913 #if defined(PETSC_USE_DEBUG)
914   {
915     PetscInt dof;
916     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
917     if (dof) PetscValidPointer(coneOrientation, 3);
918   }
919 #endif
920   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
921 
922   *coneOrientation = &mesh->coneOrientations[off];
923   PetscFunctionReturn(0);
924 }
925 
926 #undef __FUNCT__
927 #define __FUNCT__ "DMPlexSetConeOrientation"
928 /*@
929   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
930 
931   Not collective
932 
933   Input Parameters:
934 + mesh - The DMPlex
935 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
936 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
937                     integer giving the prescription for cone traversal. If it is negative, the cone is
938                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
939                     the index of the cone point on which to start.
940 
941   Output Parameter:
942 
943   Note:
944   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
945 
946   Level: beginner
947 
948 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
949 @*/
950 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
951 {
952   DM_Plex       *mesh = (DM_Plex*) dm->data;
953   PetscInt       pStart, pEnd;
954   PetscInt       dof, off, c;
955   PetscErrorCode ierr;
956 
957   PetscFunctionBegin;
958   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
959   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
960   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
961   if (dof) PetscValidPointer(coneOrientation, 3);
962   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
963   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
964   for (c = 0; c < dof; ++c) {
965     PetscInt cdof, o = coneOrientation[c];
966 
967     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
968     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
969     mesh->coneOrientations[off+c] = o;
970   }
971   PetscFunctionReturn(0);
972 }
973 
974 #undef __FUNCT__
975 #define __FUNCT__ "DMPlexInsertCone"
976 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
977 {
978   DM_Plex       *mesh = (DM_Plex*) dm->data;
979   PetscInt       pStart, pEnd;
980   PetscInt       dof, off;
981   PetscErrorCode ierr;
982 
983   PetscFunctionBegin;
984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
985   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
986   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
987   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
988   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
989   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
990   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
991   mesh->cones[off+conePos] = conePoint;
992   PetscFunctionReturn(0);
993 }
994 
995 #undef __FUNCT__
996 #define __FUNCT__ "DMPlexInsertConeOrientation"
997 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
998 {
999   DM_Plex       *mesh = (DM_Plex*) dm->data;
1000   PetscInt       pStart, pEnd;
1001   PetscInt       dof, off;
1002   PetscErrorCode ierr;
1003 
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1006   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1007   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1008   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1009   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1010   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1011   mesh->coneOrientations[off+conePos] = coneOrientation;
1012   PetscFunctionReturn(0);
1013 }
1014 
1015 #undef __FUNCT__
1016 #define __FUNCT__ "DMPlexGetSupportSize"
1017 /*@
1018   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1019 
1020   Not collective
1021 
1022   Input Parameters:
1023 + mesh - The DMPlex
1024 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1025 
1026   Output Parameter:
1027 . size - The support size for point p
1028 
1029   Level: beginner
1030 
1031 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1032 @*/
1033 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1034 {
1035   DM_Plex       *mesh = (DM_Plex*) dm->data;
1036   PetscErrorCode ierr;
1037 
1038   PetscFunctionBegin;
1039   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1040   PetscValidPointer(size, 3);
1041   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1042   PetscFunctionReturn(0);
1043 }
1044 
1045 #undef __FUNCT__
1046 #define __FUNCT__ "DMPlexSetSupportSize"
1047 /*@
1048   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1049 
1050   Not collective
1051 
1052   Input Parameters:
1053 + mesh - The DMPlex
1054 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1055 - size - The support size for point p
1056 
1057   Output Parameter:
1058 
1059   Note:
1060   This should be called after DMPlexSetChart().
1061 
1062   Level: beginner
1063 
1064 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1065 @*/
1066 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1067 {
1068   DM_Plex       *mesh = (DM_Plex*) dm->data;
1069   PetscErrorCode ierr;
1070 
1071   PetscFunctionBegin;
1072   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1073   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1074 
1075   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1076   PetscFunctionReturn(0);
1077 }
1078 
1079 #undef __FUNCT__
1080 #define __FUNCT__ "DMPlexGetSupport"
1081 /*@C
1082   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1083 
1084   Not collective
1085 
1086   Input Parameters:
1087 + mesh - The DMPlex
1088 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1089 
1090   Output Parameter:
1091 . support - An array of points which are on the out-edges for point p
1092 
1093   Level: beginner
1094 
1095   Fortran Notes:
1096   Since it returns an array, this routine is only available in Fortran 90, and you must
1097   include petsc.h90 in your code.
1098 
1099   You must also call DMPlexRestoreSupport() after you finish using the returned array.
1100 
1101 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1102 @*/
1103 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1104 {
1105   DM_Plex       *mesh = (DM_Plex*) dm->data;
1106   PetscInt       off;
1107   PetscErrorCode ierr;
1108 
1109   PetscFunctionBegin;
1110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1111   PetscValidPointer(support, 3);
1112   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1113   *support = &mesh->supports[off];
1114   PetscFunctionReturn(0);
1115 }
1116 
1117 #undef __FUNCT__
1118 #define __FUNCT__ "DMPlexSetSupport"
1119 /*@
1120   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1121 
1122   Not collective
1123 
1124   Input Parameters:
1125 + mesh - The DMPlex
1126 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1127 - support - An array of points which are on the in-edges for point p
1128 
1129   Output Parameter:
1130 
1131   Note:
1132   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1133 
1134   Level: beginner
1135 
1136 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1137 @*/
1138 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1139 {
1140   DM_Plex       *mesh = (DM_Plex*) dm->data;
1141   PetscInt       pStart, pEnd;
1142   PetscInt       dof, off, c;
1143   PetscErrorCode ierr;
1144 
1145   PetscFunctionBegin;
1146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1147   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1148   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1149   if (dof) PetscValidPointer(support, 3);
1150   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1151   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1152   for (c = 0; c < dof; ++c) {
1153     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1154     mesh->supports[off+c] = support[c];
1155   }
1156   PetscFunctionReturn(0);
1157 }
1158 
1159 #undef __FUNCT__
1160 #define __FUNCT__ "DMPlexInsertSupport"
1161 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1162 {
1163   DM_Plex       *mesh = (DM_Plex*) dm->data;
1164   PetscInt       pStart, pEnd;
1165   PetscInt       dof, off;
1166   PetscErrorCode ierr;
1167 
1168   PetscFunctionBegin;
1169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1170   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1171   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1172   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1173   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1174   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1175   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1176   mesh->supports[off+supportPos] = supportPoint;
1177   PetscFunctionReturn(0);
1178 }
1179 
1180 #undef __FUNCT__
1181 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1182 /*@C
1183   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1184 
1185   Not collective
1186 
1187   Input Parameters:
1188 + mesh - The DMPlex
1189 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1190 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1191 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1192 
1193   Output Parameters:
1194 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1195 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1196 
1197   Note:
1198   If using internal storage (points is NULL on input), each call overwrites the last output.
1199 
1200   Fortran Notes:
1201   Since it returns an array, this routine is only available in Fortran 90, and you must
1202   include petsc.h90 in your code.
1203 
1204   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1205 
1206   Level: beginner
1207 
1208 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1209 @*/
1210 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1211 {
1212   DM_Plex        *mesh = (DM_Plex*) dm->data;
1213   PetscInt       *closure, *fifo;
1214   const PetscInt *tmp = NULL, *tmpO = NULL;
1215   PetscInt        tmpSize, t;
1216   PetscInt        depth       = 0, maxSize;
1217   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1218   PetscErrorCode  ierr;
1219 
1220   PetscFunctionBegin;
1221   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1222   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1223   /* This is only 1-level */
1224   if (useCone) {
1225     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1226     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1227     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1228   } else {
1229     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1230     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1231   }
1232   if (depth == 1) {
1233     if (*points) {
1234       closure = *points;
1235     } else {
1236       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1237       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1238     }
1239     closure[0] = p; closure[1] = 0;
1240     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1241       closure[closureSize]   = tmp[t];
1242       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1243     }
1244     if (numPoints) *numPoints = closureSize/2;
1245     if (points)    *points    = closure;
1246     PetscFunctionReturn(0);
1247   }
1248   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1249   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1250   if (*points) {
1251     closure = *points;
1252   } else {
1253     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1254   }
1255   closure[0] = p; closure[1] = 0;
1256   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1257     const PetscInt cp = tmp[t];
1258     const PetscInt co = tmpO ? tmpO[t] : 0;
1259 
1260     closure[closureSize]   = cp;
1261     closure[closureSize+1] = co;
1262     fifo[fifoSize]         = cp;
1263     fifo[fifoSize+1]       = co;
1264   }
1265   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1266   while (fifoSize - fifoStart) {
1267     const PetscInt q   = fifo[fifoStart];
1268     const PetscInt o   = fifo[fifoStart+1];
1269     const PetscInt rev = o >= 0 ? 0 : 1;
1270     const PetscInt off = rev ? -(o+1) : o;
1271 
1272     if (useCone) {
1273       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1274       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1275       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1276     } else {
1277       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1278       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1279       tmpO = NULL;
1280     }
1281     for (t = 0; t < tmpSize; ++t) {
1282       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1283       const PetscInt cp = tmp[i];
1284       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1285       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1286        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1287       PetscInt       co = tmpO ? tmpO[i] : 0;
1288       PetscInt       c;
1289 
1290       if (rev) {
1291         PetscInt childSize, coff;
1292         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1293         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1294         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1295       }
1296       /* Check for duplicate */
1297       for (c = 0; c < closureSize; c += 2) {
1298         if (closure[c] == cp) break;
1299       }
1300       if (c == closureSize) {
1301         closure[closureSize]   = cp;
1302         closure[closureSize+1] = co;
1303         fifo[fifoSize]         = cp;
1304         fifo[fifoSize+1]       = co;
1305         closureSize           += 2;
1306         fifoSize              += 2;
1307       }
1308     }
1309     fifoStart += 2;
1310   }
1311   if (numPoints) *numPoints = closureSize/2;
1312   if (points)    *points    = closure;
1313   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1314   PetscFunctionReturn(0);
1315 }
1316 
1317 #undef __FUNCT__
1318 #define __FUNCT__ "DMPlexGetTransitiveClosure_Internal"
1319 /*@C
1320   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation
1321 
1322   Not collective
1323 
1324   Input Parameters:
1325 + mesh - The DMPlex
1326 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1327 . orientation - The orientation of the point
1328 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1329 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1330 
1331   Output Parameters:
1332 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1333 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1334 
1335   Note:
1336   If using internal storage (points is NULL on input), each call overwrites the last output.
1337 
1338   Fortran Notes:
1339   Since it returns an array, this routine is only available in Fortran 90, and you must
1340   include petsc.h90 in your code.
1341 
1342   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1343 
1344   Level: beginner
1345 
1346 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1347 @*/
1348 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1349 {
1350   DM_Plex        *mesh = (DM_Plex*) dm->data;
1351   PetscInt       *closure, *fifo;
1352   const PetscInt *tmp = NULL, *tmpO = NULL;
1353   PetscInt        tmpSize, t;
1354   PetscInt        depth       = 0, maxSize;
1355   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1356   PetscErrorCode  ierr;
1357 
1358   PetscFunctionBegin;
1359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1360   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1361   /* This is only 1-level */
1362   if (useCone) {
1363     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1364     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1365     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1366   } else {
1367     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1368     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1369   }
1370   if (depth == 1) {
1371     if (*points) {
1372       closure = *points;
1373     } else {
1374       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1375       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1376     }
1377     closure[0] = p; closure[1] = ornt;
1378     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1379       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1380       closure[closureSize]   = tmp[i];
1381       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1382     }
1383     if (numPoints) *numPoints = closureSize/2;
1384     if (points)    *points    = closure;
1385     PetscFunctionReturn(0);
1386   }
1387   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1388   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1389   if (*points) {
1390     closure = *points;
1391   } else {
1392     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1393   }
1394   closure[0] = p; closure[1] = ornt;
1395   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1396     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1397     const PetscInt cp = tmp[i];
1398     PetscInt       co = tmpO ? tmpO[i] : 0;
1399 
1400     if (ornt < 0) {
1401       PetscInt childSize, coff;
1402       ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1403       coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1404       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1405     }
1406     closure[closureSize]   = cp;
1407     closure[closureSize+1] = co;
1408     fifo[fifoSize]         = cp;
1409     fifo[fifoSize+1]       = co;
1410   }
1411   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1412   while (fifoSize - fifoStart) {
1413     const PetscInt q   = fifo[fifoStart];
1414     const PetscInt o   = fifo[fifoStart+1];
1415     const PetscInt rev = o >= 0 ? 0 : 1;
1416     const PetscInt off = rev ? -(o+1) : o;
1417 
1418     if (useCone) {
1419       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1420       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1421       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1422     } else {
1423       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1424       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1425       tmpO = NULL;
1426     }
1427     for (t = 0; t < tmpSize; ++t) {
1428       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1429       const PetscInt cp = tmp[i];
1430       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1431       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1432        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1433       PetscInt       co = tmpO ? tmpO[i] : 0;
1434       PetscInt       c;
1435 
1436       if (rev) {
1437         PetscInt childSize, coff;
1438         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1439         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1440         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1441       }
1442       /* Check for duplicate */
1443       for (c = 0; c < closureSize; c += 2) {
1444         if (closure[c] == cp) break;
1445       }
1446       if (c == closureSize) {
1447         closure[closureSize]   = cp;
1448         closure[closureSize+1] = co;
1449         fifo[fifoSize]         = cp;
1450         fifo[fifoSize+1]       = co;
1451         closureSize           += 2;
1452         fifoSize              += 2;
1453       }
1454     }
1455     fifoStart += 2;
1456   }
1457   if (numPoints) *numPoints = closureSize/2;
1458   if (points)    *points    = closure;
1459   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 #undef __FUNCT__
1464 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1465 /*@C
1466   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1467 
1468   Not collective
1469 
1470   Input Parameters:
1471 + mesh - The DMPlex
1472 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1473 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1474 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1475 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
1476 
1477   Note:
1478   If not using internal storage (points is not NULL on input), this call is unnecessary
1479 
1480   Fortran Notes:
1481   Since it returns an array, this routine is only available in Fortran 90, and you must
1482   include petsc.h90 in your code.
1483 
1484   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1485 
1486   Level: beginner
1487 
1488 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1489 @*/
1490 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1491 {
1492   PetscErrorCode ierr;
1493 
1494   PetscFunctionBegin;
1495   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1496   if (numPoints) PetscValidIntPointer(numPoints,4);
1497   if (points) PetscValidPointer(points,5);
1498   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1499   if (numPoints) *numPoints = 0;
1500   PetscFunctionReturn(0);
1501 }
1502 
1503 #undef __FUNCT__
1504 #define __FUNCT__ "DMPlexGetMaxSizes"
1505 /*@
1506   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1507 
1508   Not collective
1509 
1510   Input Parameter:
1511 . mesh - The DMPlex
1512 
1513   Output Parameters:
1514 + maxConeSize - The maximum number of in-edges
1515 - maxSupportSize - The maximum number of out-edges
1516 
1517   Level: beginner
1518 
1519 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1520 @*/
1521 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1522 {
1523   DM_Plex *mesh = (DM_Plex*) dm->data;
1524 
1525   PetscFunctionBegin;
1526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1527   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1528   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1529   PetscFunctionReturn(0);
1530 }
1531 
1532 #undef __FUNCT__
1533 #define __FUNCT__ "DMSetUp_Plex"
1534 PetscErrorCode DMSetUp_Plex(DM dm)
1535 {
1536   DM_Plex       *mesh = (DM_Plex*) dm->data;
1537   PetscInt       size;
1538   PetscErrorCode ierr;
1539 
1540   PetscFunctionBegin;
1541   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1542   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1543   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1544   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
1545   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
1546   if (mesh->maxSupportSize) {
1547     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1548     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1549     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
1550   }
1551   PetscFunctionReturn(0);
1552 }
1553 
1554 #undef __FUNCT__
1555 #define __FUNCT__ "DMCreateSubDM_Plex"
1556 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1557 {
1558   PetscErrorCode ierr;
1559 
1560   PetscFunctionBegin;
1561   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
1562   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1563   PetscFunctionReturn(0);
1564 }
1565 
1566 #undef __FUNCT__
1567 #define __FUNCT__ "DMPlexSymmetrize"
1568 /*@
1569   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1570 
1571   Not collective
1572 
1573   Input Parameter:
1574 . mesh - The DMPlex
1575 
1576   Output Parameter:
1577 
1578   Note:
1579   This should be called after all calls to DMPlexSetCone()
1580 
1581   Level: beginner
1582 
1583 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1584 @*/
1585 PetscErrorCode DMPlexSymmetrize(DM dm)
1586 {
1587   DM_Plex       *mesh = (DM_Plex*) dm->data;
1588   PetscInt      *offsets;
1589   PetscInt       supportSize;
1590   PetscInt       pStart, pEnd, p;
1591   PetscErrorCode ierr;
1592 
1593   PetscFunctionBegin;
1594   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1595   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1596   /* Calculate support sizes */
1597   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1598   for (p = pStart; p < pEnd; ++p) {
1599     PetscInt dof, off, c;
1600 
1601     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1602     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1603     for (c = off; c < off+dof; ++c) {
1604       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1605     }
1606   }
1607   for (p = pStart; p < pEnd; ++p) {
1608     PetscInt dof;
1609 
1610     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1611 
1612     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1613   }
1614   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1615   /* Calculate supports */
1616   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1617   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
1618   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
1619   for (p = pStart; p < pEnd; ++p) {
1620     PetscInt dof, off, c;
1621 
1622     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1623     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1624     for (c = off; c < off+dof; ++c) {
1625       const PetscInt q = mesh->cones[c];
1626       PetscInt       offS;
1627 
1628       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1629 
1630       mesh->supports[offS+offsets[q]] = p;
1631       ++offsets[q];
1632     }
1633   }
1634   ierr = PetscFree(offsets);CHKERRQ(ierr);
1635   PetscFunctionReturn(0);
1636 }
1637 
1638 #undef __FUNCT__
1639 #define __FUNCT__ "DMPlexStratify"
1640 /*@
1641   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1642   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1643   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1644   the DAG.
1645 
1646   Not collective
1647 
1648   Input Parameter:
1649 . mesh - The DMPlex
1650 
1651   Output Parameter:
1652 
1653   Notes:
1654   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1655   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1656 
1657   This should be called after all calls to DMPlexSymmetrize()
1658 
1659   Level: beginner
1660 
1661 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1662 @*/
1663 PetscErrorCode DMPlexStratify(DM dm)
1664 {
1665   DMLabel        label;
1666   PetscInt       pStart, pEnd, p;
1667   PetscInt       numRoots = 0, numLeaves = 0;
1668   PetscErrorCode ierr;
1669 
1670   PetscFunctionBegin;
1671   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1672   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1673   /* Calculate depth */
1674   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1675   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1676   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1677   /* Initialize roots and count leaves */
1678   for (p = pStart; p < pEnd; ++p) {
1679     PetscInt coneSize, supportSize;
1680 
1681     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1682     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1683     if (!coneSize && supportSize) {
1684       ++numRoots;
1685       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1686     } else if (!supportSize && coneSize) {
1687       ++numLeaves;
1688     } else if (!supportSize && !coneSize) {
1689       /* Isolated points */
1690       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1691     }
1692   }
1693   if (numRoots + numLeaves == (pEnd - pStart)) {
1694     for (p = pStart; p < pEnd; ++p) {
1695       PetscInt coneSize, supportSize;
1696 
1697       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1698       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1699       if (!supportSize && coneSize) {
1700         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1701       }
1702     }
1703   } else {
1704     IS       pointIS;
1705     PetscInt numPoints = 0, level = 0;
1706 
1707     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1708     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1709     while (numPoints) {
1710       const PetscInt *points;
1711       const PetscInt  newLevel = level+1;
1712 
1713       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1714       for (p = 0; p < numPoints; ++p) {
1715         const PetscInt  point = points[p];
1716         const PetscInt *support;
1717         PetscInt        supportSize, s;
1718 
1719         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1720         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1721         for (s = 0; s < supportSize; ++s) {
1722           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1723         }
1724       }
1725       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
1726       ++level;
1727       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1728       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1729       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1730       else         {numPoints = 0;}
1731     }
1732     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1733   }
1734   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1735   PetscFunctionReturn(0);
1736 }
1737 
1738 #undef __FUNCT__
1739 #define __FUNCT__ "DMPlexGetJoin"
1740 /*@C
1741   DMPlexGetJoin - Get an array for the join of the set of points
1742 
1743   Not Collective
1744 
1745   Input Parameters:
1746 + dm - The DMPlex object
1747 . numPoints - The number of input points for the join
1748 - points - The input points
1749 
1750   Output Parameters:
1751 + numCoveredPoints - The number of points in the join
1752 - coveredPoints - The points in the join
1753 
1754   Level: intermediate
1755 
1756   Note: Currently, this is restricted to a single level join
1757 
1758   Fortran Notes:
1759   Since it returns an array, this routine is only available in Fortran 90, and you must
1760   include petsc.h90 in your code.
1761 
1762   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1763 
1764 .keywords: mesh
1765 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1766 @*/
1767 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1768 {
1769   DM_Plex       *mesh = (DM_Plex*) dm->data;
1770   PetscInt      *join[2];
1771   PetscInt       joinSize, i = 0;
1772   PetscInt       dof, off, p, c, m;
1773   PetscErrorCode ierr;
1774 
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   PetscValidPointer(points, 2);
1778   PetscValidPointer(numCoveredPoints, 3);
1779   PetscValidPointer(coveredPoints, 4);
1780   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1781   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1782   /* Copy in support of first point */
1783   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1784   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1785   for (joinSize = 0; joinSize < dof; ++joinSize) {
1786     join[i][joinSize] = mesh->supports[off+joinSize];
1787   }
1788   /* Check each successive support */
1789   for (p = 1; p < numPoints; ++p) {
1790     PetscInt newJoinSize = 0;
1791 
1792     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1793     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1794     for (c = 0; c < dof; ++c) {
1795       const PetscInt point = mesh->supports[off+c];
1796 
1797       for (m = 0; m < joinSize; ++m) {
1798         if (point == join[i][m]) {
1799           join[1-i][newJoinSize++] = point;
1800           break;
1801         }
1802       }
1803     }
1804     joinSize = newJoinSize;
1805     i        = 1-i;
1806   }
1807   *numCoveredPoints = joinSize;
1808   *coveredPoints    = join[i];
1809   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1810   PetscFunctionReturn(0);
1811 }
1812 
1813 #undef __FUNCT__
1814 #define __FUNCT__ "DMPlexRestoreJoin"
1815 /*@C
1816   DMPlexRestoreJoin - Restore an array for the join of the set of points
1817 
1818   Not Collective
1819 
1820   Input Parameters:
1821 + dm - The DMPlex object
1822 . numPoints - The number of input points for the join
1823 - points - The input points
1824 
1825   Output Parameters:
1826 + numCoveredPoints - The number of points in the join
1827 - coveredPoints - The points in the join
1828 
1829   Fortran Notes:
1830   Since it returns an array, this routine is only available in Fortran 90, and you must
1831   include petsc.h90 in your code.
1832 
1833   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1834 
1835   Level: intermediate
1836 
1837 .keywords: mesh
1838 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1839 @*/
1840 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1841 {
1842   PetscErrorCode ierr;
1843 
1844   PetscFunctionBegin;
1845   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1846   if (points) PetscValidIntPointer(points,3);
1847   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
1848   PetscValidPointer(coveredPoints, 5);
1849   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1850   if (numCoveredPoints) *numCoveredPoints = 0;
1851   PetscFunctionReturn(0);
1852 }
1853 
1854 #undef __FUNCT__
1855 #define __FUNCT__ "DMPlexGetFullJoin"
1856 /*@C
1857   DMPlexGetFullJoin - Get an array for the join of the set of points
1858 
1859   Not Collective
1860 
1861   Input Parameters:
1862 + dm - The DMPlex object
1863 . numPoints - The number of input points for the join
1864 - points - The input points
1865 
1866   Output Parameters:
1867 + numCoveredPoints - The number of points in the join
1868 - coveredPoints - The points in the join
1869 
1870   Fortran Notes:
1871   Since it returns an array, this routine is only available in Fortran 90, and you must
1872   include petsc.h90 in your code.
1873 
1874   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1875 
1876   Level: intermediate
1877 
1878 .keywords: mesh
1879 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1880 @*/
1881 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1882 {
1883   DM_Plex       *mesh = (DM_Plex*) dm->data;
1884   PetscInt      *offsets, **closures;
1885   PetscInt      *join[2];
1886   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1887   PetscInt       p, d, c, m;
1888   PetscErrorCode ierr;
1889 
1890   PetscFunctionBegin;
1891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1892   PetscValidPointer(points, 2);
1893   PetscValidPointer(numCoveredPoints, 3);
1894   PetscValidPointer(coveredPoints, 4);
1895 
1896   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1897   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
1898   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1899   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1900   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1901   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1902 
1903   for (p = 0; p < numPoints; ++p) {
1904     PetscInt closureSize;
1905 
1906     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1907 
1908     offsets[p*(depth+2)+0] = 0;
1909     for (d = 0; d < depth+1; ++d) {
1910       PetscInt pStart, pEnd, i;
1911 
1912       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1913       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1914         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1915           offsets[p*(depth+2)+d+1] = i;
1916           break;
1917         }
1918       }
1919       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1920     }
1921     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
1922   }
1923   for (d = 0; d < depth+1; ++d) {
1924     PetscInt dof;
1925 
1926     /* Copy in support of first point */
1927     dof = offsets[d+1] - offsets[d];
1928     for (joinSize = 0; joinSize < dof; ++joinSize) {
1929       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1930     }
1931     /* Check each successive cone */
1932     for (p = 1; p < numPoints && joinSize; ++p) {
1933       PetscInt newJoinSize = 0;
1934 
1935       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1936       for (c = 0; c < dof; ++c) {
1937         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1938 
1939         for (m = 0; m < joinSize; ++m) {
1940           if (point == join[i][m]) {
1941             join[1-i][newJoinSize++] = point;
1942             break;
1943           }
1944         }
1945       }
1946       joinSize = newJoinSize;
1947       i        = 1-i;
1948     }
1949     if (joinSize) break;
1950   }
1951   *numCoveredPoints = joinSize;
1952   *coveredPoints    = join[i];
1953   for (p = 0; p < numPoints; ++p) {
1954     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1955   }
1956   ierr = PetscFree(closures);CHKERRQ(ierr);
1957   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1958   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1959   PetscFunctionReturn(0);
1960 }
1961 
1962 #undef __FUNCT__
1963 #define __FUNCT__ "DMPlexGetMeet"
1964 /*@C
1965   DMPlexGetMeet - Get an array for the meet of the set of points
1966 
1967   Not Collective
1968 
1969   Input Parameters:
1970 + dm - The DMPlex object
1971 . numPoints - The number of input points for the meet
1972 - points - The input points
1973 
1974   Output Parameters:
1975 + numCoveredPoints - The number of points in the meet
1976 - coveredPoints - The points in the meet
1977 
1978   Level: intermediate
1979 
1980   Note: Currently, this is restricted to a single level meet
1981 
1982   Fortran Notes:
1983   Since it returns an array, this routine is only available in Fortran 90, and you must
1984   include petsc.h90 in your code.
1985 
1986   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1987 
1988 .keywords: mesh
1989 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1990 @*/
1991 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1992 {
1993   DM_Plex       *mesh = (DM_Plex*) dm->data;
1994   PetscInt      *meet[2];
1995   PetscInt       meetSize, i = 0;
1996   PetscInt       dof, off, p, c, m;
1997   PetscErrorCode ierr;
1998 
1999   PetscFunctionBegin;
2000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2001   PetscValidPointer(points, 2);
2002   PetscValidPointer(numCoveringPoints, 3);
2003   PetscValidPointer(coveringPoints, 4);
2004   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2005   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2006   /* Copy in cone of first point */
2007   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2008   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2009   for (meetSize = 0; meetSize < dof; ++meetSize) {
2010     meet[i][meetSize] = mesh->cones[off+meetSize];
2011   }
2012   /* Check each successive cone */
2013   for (p = 1; p < numPoints; ++p) {
2014     PetscInt newMeetSize = 0;
2015 
2016     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2017     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2018     for (c = 0; c < dof; ++c) {
2019       const PetscInt point = mesh->cones[off+c];
2020 
2021       for (m = 0; m < meetSize; ++m) {
2022         if (point == meet[i][m]) {
2023           meet[1-i][newMeetSize++] = point;
2024           break;
2025         }
2026       }
2027     }
2028     meetSize = newMeetSize;
2029     i        = 1-i;
2030   }
2031   *numCoveringPoints = meetSize;
2032   *coveringPoints    = meet[i];
2033   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2034   PetscFunctionReturn(0);
2035 }
2036 
2037 #undef __FUNCT__
2038 #define __FUNCT__ "DMPlexRestoreMeet"
2039 /*@C
2040   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2041 
2042   Not Collective
2043 
2044   Input Parameters:
2045 + dm - The DMPlex object
2046 . numPoints - The number of input points for the meet
2047 - points - The input points
2048 
2049   Output Parameters:
2050 + numCoveredPoints - The number of points in the meet
2051 - coveredPoints - The points in the meet
2052 
2053   Level: intermediate
2054 
2055   Fortran Notes:
2056   Since it returns an array, this routine is only available in Fortran 90, and you must
2057   include petsc.h90 in your code.
2058 
2059   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2060 
2061 .keywords: mesh
2062 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2063 @*/
2064 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2065 {
2066   PetscErrorCode ierr;
2067 
2068   PetscFunctionBegin;
2069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2070   if (points) PetscValidIntPointer(points,3);
2071   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2072   PetscValidPointer(coveredPoints,5);
2073   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2074   if (numCoveredPoints) *numCoveredPoints = 0;
2075   PetscFunctionReturn(0);
2076 }
2077 
2078 #undef __FUNCT__
2079 #define __FUNCT__ "DMPlexGetFullMeet"
2080 /*@C
2081   DMPlexGetFullMeet - Get an array for the meet of the set of points
2082 
2083   Not Collective
2084 
2085   Input Parameters:
2086 + dm - The DMPlex object
2087 . numPoints - The number of input points for the meet
2088 - points - The input points
2089 
2090   Output Parameters:
2091 + numCoveredPoints - The number of points in the meet
2092 - coveredPoints - The points in the meet
2093 
2094   Level: intermediate
2095 
2096   Fortran Notes:
2097   Since it returns an array, this routine is only available in Fortran 90, and you must
2098   include petsc.h90 in your code.
2099 
2100   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2101 
2102 .keywords: mesh
2103 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2104 @*/
2105 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2106 {
2107   DM_Plex       *mesh = (DM_Plex*) dm->data;
2108   PetscInt      *offsets, **closures;
2109   PetscInt      *meet[2];
2110   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2111   PetscInt       p, h, c, m;
2112   PetscErrorCode ierr;
2113 
2114   PetscFunctionBegin;
2115   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2116   PetscValidPointer(points, 2);
2117   PetscValidPointer(numCoveredPoints, 3);
2118   PetscValidPointer(coveredPoints, 4);
2119 
2120   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2121   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
2122   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2123   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
2124   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2125   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2126 
2127   for (p = 0; p < numPoints; ++p) {
2128     PetscInt closureSize;
2129 
2130     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2131 
2132     offsets[p*(height+2)+0] = 0;
2133     for (h = 0; h < height+1; ++h) {
2134       PetscInt pStart, pEnd, i;
2135 
2136       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2137       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2138         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2139           offsets[p*(height+2)+h+1] = i;
2140           break;
2141         }
2142       }
2143       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2144     }
2145     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2146   }
2147   for (h = 0; h < height+1; ++h) {
2148     PetscInt dof;
2149 
2150     /* Copy in cone of first point */
2151     dof = offsets[h+1] - offsets[h];
2152     for (meetSize = 0; meetSize < dof; ++meetSize) {
2153       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2154     }
2155     /* Check each successive cone */
2156     for (p = 1; p < numPoints && meetSize; ++p) {
2157       PetscInt newMeetSize = 0;
2158 
2159       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2160       for (c = 0; c < dof; ++c) {
2161         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2162 
2163         for (m = 0; m < meetSize; ++m) {
2164           if (point == meet[i][m]) {
2165             meet[1-i][newMeetSize++] = point;
2166             break;
2167           }
2168         }
2169       }
2170       meetSize = newMeetSize;
2171       i        = 1-i;
2172     }
2173     if (meetSize) break;
2174   }
2175   *numCoveredPoints = meetSize;
2176   *coveredPoints    = meet[i];
2177   for (p = 0; p < numPoints; ++p) {
2178     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2179   }
2180   ierr = PetscFree(closures);CHKERRQ(ierr);
2181   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2182   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2183   PetscFunctionReturn(0);
2184 }
2185 
2186 #undef __FUNCT__
2187 #define __FUNCT__ "DMPlexEqual"
2188 /*@C
2189   DMPlexEqual - Determine if two DMs have the same topology
2190 
2191   Not Collective
2192 
2193   Input Parameters:
2194 + dmA - A DMPlex object
2195 - dmB - A DMPlex object
2196 
2197   Output Parameters:
2198 . equal - PETSC_TRUE if the topologies are identical
2199 
2200   Level: intermediate
2201 
2202   Notes:
2203   We are not solving graph isomorphism, so we do not permutation.
2204 
2205 .keywords: mesh
2206 .seealso: DMPlexGetCone()
2207 @*/
2208 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2209 {
2210   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2211   PetscErrorCode ierr;
2212 
2213   PetscFunctionBegin;
2214   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
2215   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
2216   PetscValidPointer(equal, 3);
2217 
2218   *equal = PETSC_FALSE;
2219   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
2220   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
2221   if (depth != depthB) PetscFunctionReturn(0);
2222   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
2223   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
2224   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
2225   for (p = pStart; p < pEnd; ++p) {
2226     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2227     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2228 
2229     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
2230     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
2231     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
2232     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
2233     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
2234     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
2235     if (coneSize != coneSizeB) PetscFunctionReturn(0);
2236     for (c = 0; c < coneSize; ++c) {
2237       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
2238       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
2239     }
2240     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
2241     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
2242     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
2243     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
2244     if (supportSize != supportSizeB) PetscFunctionReturn(0);
2245     for (s = 0; s < supportSize; ++s) {
2246       if (support[s] != supportB[s]) PetscFunctionReturn(0);
2247     }
2248   }
2249   *equal = PETSC_TRUE;
2250   PetscFunctionReturn(0);
2251 }
2252 
2253 #undef __FUNCT__
2254 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2255 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2256 {
2257   MPI_Comm       comm;
2258   PetscErrorCode ierr;
2259 
2260   PetscFunctionBegin;
2261   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2262   PetscValidPointer(numFaceVertices,3);
2263   switch (cellDim) {
2264   case 0:
2265     *numFaceVertices = 0;
2266     break;
2267   case 1:
2268     *numFaceVertices = 1;
2269     break;
2270   case 2:
2271     switch (numCorners) {
2272     case 3: /* triangle */
2273       *numFaceVertices = 2; /* Edge has 2 vertices */
2274       break;
2275     case 4: /* quadrilateral */
2276       *numFaceVertices = 2; /* Edge has 2 vertices */
2277       break;
2278     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2279       *numFaceVertices = 3; /* Edge has 3 vertices */
2280       break;
2281     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2282       *numFaceVertices = 3; /* Edge has 3 vertices */
2283       break;
2284     default:
2285       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2286     }
2287     break;
2288   case 3:
2289     switch (numCorners) {
2290     case 4: /* tetradehdron */
2291       *numFaceVertices = 3; /* Face has 3 vertices */
2292       break;
2293     case 6: /* tet cohesive cells */
2294       *numFaceVertices = 4; /* Face has 4 vertices */
2295       break;
2296     case 8: /* hexahedron */
2297       *numFaceVertices = 4; /* Face has 4 vertices */
2298       break;
2299     case 9: /* tet cohesive Lagrange cells */
2300       *numFaceVertices = 6; /* Face has 6 vertices */
2301       break;
2302     case 10: /* quadratic tetrahedron */
2303       *numFaceVertices = 6; /* Face has 6 vertices */
2304       break;
2305     case 12: /* hex cohesive Lagrange cells */
2306       *numFaceVertices = 6; /* Face has 6 vertices */
2307       break;
2308     case 18: /* quadratic tet cohesive Lagrange cells */
2309       *numFaceVertices = 6; /* Face has 6 vertices */
2310       break;
2311     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2312       *numFaceVertices = 9; /* Face has 9 vertices */
2313       break;
2314     default:
2315       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2316     }
2317     break;
2318   default:
2319     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2320   }
2321   PetscFunctionReturn(0);
2322 }
2323 
2324 #undef __FUNCT__
2325 #define __FUNCT__ "DMPlexOrient"
2326 /* Trys to give the mesh a consistent orientation */
2327 PetscErrorCode DMPlexOrient(DM dm)
2328 {
2329   PetscBT        seenCells, flippedCells, seenFaces;
2330   PetscInt      *faceFIFO, fTop, fBottom;
2331   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
2332   PetscErrorCode ierr;
2333 
2334   PetscFunctionBegin;
2335   /* Truth Table
2336      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2337          F       0 flips     no         F             F           F
2338          F       1 flip      yes        F             T           T
2339          F       2 flips     no         T             F           T
2340          T       0 flips     yes        T             T           F
2341          T       1 flip      no
2342          T       2 flips     yes
2343   */
2344   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2345   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
2346   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
2347   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
2348   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
2349   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
2350   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
2351   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
2352   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
2353   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
2354   ierr = PetscMalloc1((fEnd - fStart), &faceFIFO);CHKERRQ(ierr);
2355   fTop = fBottom = 0;
2356   /* Initialize FIFO with first cell */
2357   if (cEnd > cStart) {
2358     const PetscInt *cone;
2359     PetscInt        coneSize;
2360 
2361     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
2362     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2363     for (c = 0; c < coneSize; ++c) {
2364       faceFIFO[fBottom++] = cone[c];
2365       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2366     }
2367   }
2368   /* Consider each face in FIFO */
2369   while (fTop < fBottom) {
2370     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2371     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2372     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2373 
2374     face = faceFIFO[fTop++];
2375     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2376     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2377     if (supportSize < 2) continue;
2378     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2379     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2380     flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2381     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2382     flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
2383 
2384     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2385     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2386     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2387     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2388     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2389     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2390     for (c = 0; c < coneSizeA; ++c) {
2391       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2392         faceFIFO[fBottom++] = coneA[c];
2393         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2394       }
2395       if (coneA[c] == face) posA = c;
2396       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2397     }
2398     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2399     for (c = 0; c < coneSizeB; ++c) {
2400       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2401         faceFIFO[fBottom++] = coneB[c];
2402         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2403       }
2404       if (coneB[c] == face) posB = c;
2405       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2406     }
2407     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2408 
2409     if (dim == 1) {
2410       mismatch = posA == posB;
2411     } else {
2412       mismatch = coneOA[posA] == coneOB[posB];
2413     }
2414 
2415     if (mismatch ^ (flippedA ^ flippedB)) {
2416       if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
2417       if (!seenA && !flippedA) {
2418         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2419       } else if (!seenB && !flippedB) {
2420         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2421       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2422     } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2423     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2424     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2425   }
2426   /* Now all subdomains are oriented, but we need a consistent parallel orientation */
2427   {
2428     /* Find a representative face (edge) separating pairs of procs */
2429     PetscSF            sf;
2430     const PetscInt    *lpoints;
2431     const PetscSFNode *rpoints;
2432     PetscInt          *neighbors, *nranks;
2433     PetscInt           numLeaves, numRoots, numNeighbors = 0, l, n;
2434 
2435     ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2436     ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints);CHKERRQ(ierr);
2437     if (numLeaves >= 0) {
2438       const PetscInt *cone, *ornt, *support;
2439       PetscInt        coneSize, supportSize;
2440       int            *rornt, *lornt; /* PetscSF cannot handle smaller than int */
2441       PetscBool      *match, flipped = PETSC_FALSE;
2442 
2443       ierr = PetscMalloc1(numLeaves,&neighbors);CHKERRQ(ierr);
2444       /* I know this is p^2 time in general, but for bounded degree its alright */
2445       for (l = 0; l < numLeaves; ++l) {
2446         const PetscInt face = lpoints[l];
2447         if ((face >= fStart) && (face < fEnd)) {
2448           const PetscInt rank = rpoints[l].rank;
2449           for (n = 0; n < numNeighbors; ++n) if (rank == rpoints[neighbors[n]].rank) break;
2450           if (n >= numNeighbors) {
2451             PetscInt supportSize;
2452             ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2453             if (supportSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %d", supportSize);
2454             neighbors[numNeighbors++] = l;
2455           }
2456         }
2457       }
2458       ierr = PetscCalloc4(numNeighbors,&match,numNeighbors,&nranks,numRoots,&rornt,numRoots,&lornt);CHKERRQ(ierr);
2459       for (face = fStart; face < fEnd; ++face) {
2460         ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2461         if (supportSize != 1) continue;
2462         ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2463 
2464         ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr);
2465         ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr);
2466         ierr = DMPlexGetConeOrientation(dm, support[0], &ornt);CHKERRQ(ierr);
2467         for (c = 0; c < coneSize; ++c) if (cone[c] == face) break;
2468         if (dim == 1) {
2469           /* Use cone position instead, shifted to -1 or 1 */
2470           rornt[face] = c*2-1;
2471         } else {
2472           if (PetscBTLookup(flippedCells, support[0]-cStart)) rornt[face] = ornt[c] < 0 ? -1 :  1;
2473           else                                                rornt[face] = ornt[c] < 0 ?  1 : -1;
2474         }
2475       }
2476       /* Mark each edge with match or nomatch */
2477       ierr = PetscSFBcastBegin(sf, MPI_INT, rornt, lornt);CHKERRQ(ierr);
2478       ierr = PetscSFBcastEnd(sf, MPI_INT, rornt, lornt);CHKERRQ(ierr);
2479       for (n = 0; n < numNeighbors; ++n) {
2480         const PetscInt face = lpoints[neighbors[n]];
2481 
2482         if (rornt[face]*lornt[face] < 0) match[n] = PETSC_TRUE;
2483         else                             match[n] = PETSC_FALSE;
2484         nranks[n] = rpoints[neighbors[n]].rank;
2485       }
2486       /* Collect the graph on 0 */
2487       {
2488         MPI_Comm     comm = PetscObjectComm((PetscObject) sf);
2489         PetscBT      seenProcs, flippedProcs;
2490         PetscInt    *procFIFO, pTop, pBottom;
2491         PetscInt    *adj = NULL;
2492         PetscBool   *val = NULL;
2493         PetscMPIInt *recvcounts = NULL, *displs = NULL, p;
2494         PetscMPIInt  N = numNeighbors, numProcs = 0, rank;
2495         PetscInt     debug = 0;
2496 
2497         ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2498         if (!rank) {ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);}
2499         ierr = PetscCalloc2(numProcs,&recvcounts,numProcs+1,&displs);CHKERRQ(ierr);
2500         ierr = MPI_Gather(&N, 1, MPI_INT, recvcounts, 1, MPI_INT, 0, comm);CHKERRQ(ierr);
2501         for (p = 0; p < numProcs; ++p) {
2502           displs[p+1] = displs[p] + recvcounts[p];
2503         }
2504         if (!rank) {ierr = PetscMalloc2(displs[numProcs],&adj,displs[numProcs],&val);CHKERRQ(ierr);}
2505         ierr = MPI_Gatherv(nranks, numNeighbors, MPIU_INT, adj, recvcounts, displs, MPIU_INT, 0, comm);CHKERRQ(ierr);
2506         ierr = MPI_Gatherv(match, numNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm);CHKERRQ(ierr);
2507         if (debug) {
2508           for (p = 0; p < numProcs; ++p) {
2509             ierr = PetscPrintf(comm, "Proc %d:\n", p);
2510             for (n = 0; n < recvcounts[p]; ++n) {
2511               ierr = PetscPrintf(comm, "  edge %d (%d):\n", adj[displs[p]+n], val[displs[p]+n]);
2512             }
2513           }
2514         }
2515         ierr = PetscBTCreate(numProcs, &seenProcs);CHKERRQ(ierr);
2516         ierr = PetscBTMemzero(numProcs, seenProcs);CHKERRQ(ierr);
2517         ierr = PetscBTCreate(numProcs, &flippedProcs);CHKERRQ(ierr);
2518         ierr = PetscBTMemzero(numProcs, flippedProcs);CHKERRQ(ierr);
2519         ierr = PetscMalloc1(numProcs,&procFIFO);CHKERRQ(ierr);
2520         pTop = pBottom = 0;
2521         for (p = 0; p < numProcs; ++p) {
2522           if (PetscBTLookup(seenProcs, p)) continue;
2523           /* Initialize FIFO with next proc */
2524           procFIFO[pBottom++] = p;
2525           ierr = PetscBTSet(seenProcs, p);CHKERRQ(ierr);
2526           /* Consider each proc in FIFO */
2527           while (pTop < pBottom) {
2528             PetscInt proc, nproc, seen, flippedA, flippedB, mismatch;
2529 
2530             proc     = procFIFO[pTop++];
2531             flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0;
2532             /* Loop over neighboring procs */
2533             for (n = 0; n < recvcounts[proc]; ++n) {
2534               nproc    = adj[displs[proc]+n];
2535               mismatch = val[displs[proc]+n] ? 0 : 1;
2536               seen     = PetscBTLookup(seenProcs, nproc);
2537               flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0;
2538 
2539               if (mismatch ^ (flippedA ^ flippedB)) {
2540                 if (seen) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %d and %d do not match: Fault mesh is non-orientable", proc, nproc);
2541                 if (!flippedB) {
2542                   ierr = PetscBTSet(flippedProcs, nproc);CHKERRQ(ierr);
2543               } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2544               } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2545               if (!seen) {
2546                 procFIFO[pBottom++] = nproc;
2547                 ierr = PetscBTSet(seenProcs, nproc);CHKERRQ(ierr);
2548               }
2549             }
2550           }
2551         }
2552         ierr = PetscFree(procFIFO);CHKERRQ(ierr);
2553 
2554         ierr = PetscFree2(recvcounts,displs);CHKERRQ(ierr);
2555         ierr = PetscFree2(adj,val);CHKERRQ(ierr);
2556         {
2557           PetscBool *flips;
2558 
2559           ierr = PetscMalloc1(numProcs,&flips);CHKERRQ(ierr);
2560           for (p = 0; p < numProcs; ++p) {
2561             flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE;
2562             if (debug && flips[p]) {ierr = PetscPrintf(comm, "Flipping Proc %d:\n", p);}
2563           }
2564           ierr = MPI_Scatter(flips, 1, MPIU_BOOL, &flipped, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr);
2565           ierr = PetscFree(flips);CHKERRQ(ierr);
2566         }
2567         ierr = PetscBTDestroy(&seenProcs);CHKERRQ(ierr);
2568         ierr = PetscBTDestroy(&flippedProcs);CHKERRQ(ierr);
2569       }
2570       ierr = PetscFree4(match,nranks,rornt,lornt);CHKERRQ(ierr);
2571       ierr = PetscFree(neighbors);CHKERRQ(ierr);
2572       if (flipped) {for (c = cStart; c < cEnd; ++c) {ierr = PetscBTNegate(flippedCells, c-cStart);CHKERRQ(ierr);}}
2573     }
2574   }
2575   /* Reverse flipped cells in the mesh */
2576   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2577   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2578   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2579   for (c = cStart; c < cEnd; ++c) {
2580     const PetscInt *cone, *coneO, *support;
2581     PetscInt        coneSize, supportSize, faceSize, cp, sp;
2582 
2583     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2584     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2585     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2586     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2587     for (cp = 0; cp < coneSize; ++cp) {
2588       const PetscInt rcp = coneSize-cp-1;
2589 
2590       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2591       revcone[cp]  = cone[rcp];
2592       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2593     }
2594     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2595     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2596     /* Reverse orientations of support */
2597     faceSize = coneSize;
2598     ierr = DMPlexGetSupportSize(dm, c, &supportSize);CHKERRQ(ierr);
2599     ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
2600     for (sp = 0; sp < supportSize; ++sp) {
2601       ierr = DMPlexGetConeSize(dm, support[sp], &coneSize);CHKERRQ(ierr);
2602       ierr = DMPlexGetCone(dm, support[sp], &cone);CHKERRQ(ierr);
2603       ierr = DMPlexGetConeOrientation(dm, support[sp], &coneO);CHKERRQ(ierr);
2604       for (cp = 0; cp < coneSize; ++cp) {
2605         if (cone[cp] != c) continue;
2606         ierr = DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);CHKERRQ(ierr);
2607       }
2608     }
2609   }
2610   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2611   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2612   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2613   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2614   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2615   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2616   PetscFunctionReturn(0);
2617 }
2618 
2619 #undef __FUNCT__
2620 #define __FUNCT__ "DMPlexInvertCell_Internal"
2621 PetscErrorCode DMPlexInvertCell_Internal(PetscInt dim, PetscInt numCorners, PetscInt cone[])
2622 {
2623   int tmpc;
2624 
2625   PetscFunctionBegin;
2626   if (dim != 3) PetscFunctionReturn(0);
2627   switch (numCorners) {
2628   case 4:
2629     tmpc    = cone[0];
2630     cone[0] = cone[1];
2631     cone[1] = tmpc;
2632     break;
2633   case 8:
2634     tmpc    = cone[1];
2635     cone[1] = cone[3];
2636     cone[3] = tmpc;
2637     break;
2638   default: break;
2639   }
2640   PetscFunctionReturn(0);
2641 }
2642 
2643 #undef __FUNCT__
2644 #define __FUNCT__ "DMPlexInvertCell"
2645 /*@C
2646   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
2647 
2648   Input Parameters:
2649 + numCorners - The number of vertices in a cell
2650 - cone - The incoming cone
2651 
2652   Output Parameter:
2653 . cone - The inverted cone (in-place)
2654 
2655   Level: developer
2656 
2657 .seealso: DMPlexGenerate()
2658 @*/
2659 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
2660 {
2661   int tmpc;
2662 
2663   PetscFunctionBegin;
2664   if (dim != 3) PetscFunctionReturn(0);
2665   switch (numCorners) {
2666   case 4:
2667     tmpc    = cone[0];
2668     cone[0] = cone[1];
2669     cone[1] = tmpc;
2670     break;
2671   case 8:
2672     tmpc    = cone[1];
2673     cone[1] = cone[3];
2674     cone[3] = tmpc;
2675     break;
2676   default: break;
2677   }
2678   PetscFunctionReturn(0);
2679 }
2680 
2681 #undef __FUNCT__
2682 #define __FUNCT__ "DMPlexInvertCells_Internal"
2683 /* This is to fix the tetrahedron orientation from TetGen */
2684 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
2685 {
2686   PetscInt       bound = numCells*numCorners, coff;
2687   PetscErrorCode ierr;
2688 
2689   PetscFunctionBegin;
2690   for (coff = 0; coff < bound; coff += numCorners) {
2691     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
2692   }
2693   PetscFunctionReturn(0);
2694 }
2695 
2696 #if defined(PETSC_HAVE_TRIANGLE)
2697 #include <triangle.h>
2698 
2699 #undef __FUNCT__
2700 #define __FUNCT__ "InitInput_Triangle"
2701 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
2702 {
2703   PetscFunctionBegin;
2704   inputCtx->numberofpoints             = 0;
2705   inputCtx->numberofpointattributes    = 0;
2706   inputCtx->pointlist                  = NULL;
2707   inputCtx->pointattributelist         = NULL;
2708   inputCtx->pointmarkerlist            = NULL;
2709   inputCtx->numberofsegments           = 0;
2710   inputCtx->segmentlist                = NULL;
2711   inputCtx->segmentmarkerlist          = NULL;
2712   inputCtx->numberoftriangleattributes = 0;
2713   inputCtx->trianglelist               = NULL;
2714   inputCtx->numberofholes              = 0;
2715   inputCtx->holelist                   = NULL;
2716   inputCtx->numberofregions            = 0;
2717   inputCtx->regionlist                 = NULL;
2718   PetscFunctionReturn(0);
2719 }
2720 
2721 #undef __FUNCT__
2722 #define __FUNCT__ "InitOutput_Triangle"
2723 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
2724 {
2725   PetscFunctionBegin;
2726   outputCtx->numberofpoints        = 0;
2727   outputCtx->pointlist             = NULL;
2728   outputCtx->pointattributelist    = NULL;
2729   outputCtx->pointmarkerlist       = NULL;
2730   outputCtx->numberoftriangles     = 0;
2731   outputCtx->trianglelist          = NULL;
2732   outputCtx->triangleattributelist = NULL;
2733   outputCtx->neighborlist          = NULL;
2734   outputCtx->segmentlist           = NULL;
2735   outputCtx->segmentmarkerlist     = NULL;
2736   outputCtx->numberofedges         = 0;
2737   outputCtx->edgelist              = NULL;
2738   outputCtx->edgemarkerlist        = NULL;
2739   PetscFunctionReturn(0);
2740 }
2741 
2742 #undef __FUNCT__
2743 #define __FUNCT__ "FiniOutput_Triangle"
2744 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
2745 {
2746   PetscFunctionBegin;
2747   free(outputCtx->pointlist);
2748   free(outputCtx->pointmarkerlist);
2749   free(outputCtx->segmentlist);
2750   free(outputCtx->segmentmarkerlist);
2751   free(outputCtx->edgelist);
2752   free(outputCtx->edgemarkerlist);
2753   free(outputCtx->trianglelist);
2754   free(outputCtx->neighborlist);
2755   PetscFunctionReturn(0);
2756 }
2757 
2758 #undef __FUNCT__
2759 #define __FUNCT__ "DMPlexGenerate_Triangle"
2760 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
2761 {
2762   MPI_Comm             comm;
2763   PetscInt             dim              = 2;
2764   const PetscBool      createConvexHull = PETSC_FALSE;
2765   const PetscBool      constrained      = PETSC_FALSE;
2766   struct triangulateio in;
2767   struct triangulateio out;
2768   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
2769   PetscMPIInt          rank;
2770   PetscErrorCode       ierr;
2771 
2772   PetscFunctionBegin;
2773   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
2774   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2775   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
2776   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
2777   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
2778 
2779   in.numberofpoints = vEnd - vStart;
2780   if (in.numberofpoints > 0) {
2781     PetscSection coordSection;
2782     Vec          coordinates;
2783     PetscScalar *array;
2784 
2785     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
2786     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
2787     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
2788     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
2789     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
2790     for (v = vStart; v < vEnd; ++v) {
2791       const PetscInt idx = v - vStart;
2792       PetscInt       off, d;
2793 
2794       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
2795       for (d = 0; d < dim; ++d) {
2796         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
2797       }
2798       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
2799     }
2800     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
2801   }
2802   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
2803   in.numberofsegments = eEnd - eStart;
2804   if (in.numberofsegments > 0) {
2805     ierr = PetscMalloc1(in.numberofsegments*2, &in.segmentlist);CHKERRQ(ierr);
2806     ierr = PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);CHKERRQ(ierr);
2807     for (e = eStart; e < eEnd; ++e) {
2808       const PetscInt  idx = e - eStart;
2809       const PetscInt *cone;
2810 
2811       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
2812 
2813       in.segmentlist[idx*2+0] = cone[0] - vStart;
2814       in.segmentlist[idx*2+1] = cone[1] - vStart;
2815 
2816       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
2817     }
2818   }
2819 #if 0 /* Do not currently support holes */
2820   PetscReal *holeCoords;
2821   PetscInt   h, d;
2822 
2823   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
2824   if (in.numberofholes > 0) {
2825     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
2826     for (h = 0; h < in.numberofholes; ++h) {
2827       for (d = 0; d < dim; ++d) {
2828         in.holelist[h*dim+d] = holeCoords[h*dim+d];
2829       }
2830     }
2831   }
2832 #endif
2833   if (!rank) {
2834     char args[32];
2835 
2836     /* Take away 'Q' for verbose output */
2837     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
2838     if (createConvexHull) {
2839       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
2840     }
2841     if (constrained) {
2842       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
2843     }
2844     triangulate(args, &in, &out, NULL);
2845   }
2846   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
2847   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
2848   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
2849   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
2850   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
2851 
2852   {
2853     const PetscInt numCorners  = 3;
2854     const PetscInt numCells    = out.numberoftriangles;
2855     const PetscInt numVertices = out.numberofpoints;
2856     const int     *cells      = out.trianglelist;
2857     const double  *meshCoords = out.pointlist;
2858 
2859     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
2860     /* Set labels */
2861     for (v = 0; v < numVertices; ++v) {
2862       if (out.pointmarkerlist[v]) {
2863         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
2864       }
2865     }
2866     if (interpolate) {
2867       for (e = 0; e < out.numberofedges; e++) {
2868         if (out.edgemarkerlist[e]) {
2869           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
2870           const PetscInt *edges;
2871           PetscInt        numEdges;
2872 
2873           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
2874           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
2875           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
2876           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
2877         }
2878       }
2879     }
2880     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
2881   }
2882 #if 0 /* Do not currently support holes */
2883   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
2884 #endif
2885   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
2886   PetscFunctionReturn(0);
2887 }
2888 
2889 #undef __FUNCT__
2890 #define __FUNCT__ "DMPlexRefine_Triangle"
2891 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
2892 {
2893   MPI_Comm             comm;
2894   PetscInt             dim  = 2;
2895   struct triangulateio in;
2896   struct triangulateio out;
2897   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
2898   PetscMPIInt          rank;
2899   PetscErrorCode       ierr;
2900 
2901   PetscFunctionBegin;
2902   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2903   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2904   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
2905   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
2906   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2907   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
2908   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
2909 
2910   in.numberofpoints = vEnd - vStart;
2911   if (in.numberofpoints > 0) {
2912     PetscSection coordSection;
2913     Vec          coordinates;
2914     PetscScalar *array;
2915 
2916     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
2917     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
2918     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
2919     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2920     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
2921     for (v = vStart; v < vEnd; ++v) {
2922       const PetscInt idx = v - vStart;
2923       PetscInt       off, d;
2924 
2925       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
2926       for (d = 0; d < dim; ++d) {
2927         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
2928       }
2929       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
2930     }
2931     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
2932   }
2933   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2934 
2935   in.numberofcorners   = 3;
2936   in.numberoftriangles = cEnd - cStart;
2937 
2938   in.trianglearealist  = (double*) maxVolumes;
2939   if (in.numberoftriangles > 0) {
2940     ierr = PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);CHKERRQ(ierr);
2941     for (c = cStart; c < cEnd; ++c) {
2942       const PetscInt idx      = c - cStart;
2943       PetscInt      *closure = NULL;
2944       PetscInt       closureSize;
2945 
2946       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2947       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
2948       for (v = 0; v < 3; ++v) {
2949         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
2950       }
2951       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2952     }
2953   }
2954   /* TODO: Segment markers are missing on input */
2955 #if 0 /* Do not currently support holes */
2956   PetscReal *holeCoords;
2957   PetscInt   h, d;
2958 
2959   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
2960   if (in.numberofholes > 0) {
2961     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
2962     for (h = 0; h < in.numberofholes; ++h) {
2963       for (d = 0; d < dim; ++d) {
2964         in.holelist[h*dim+d] = holeCoords[h*dim+d];
2965       }
2966     }
2967   }
2968 #endif
2969   if (!rank) {
2970     char args[32];
2971 
2972     /* Take away 'Q' for verbose output */
2973     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
2974     triangulate(args, &in, &out, NULL);
2975   }
2976   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
2977   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
2978   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
2979   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
2980   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
2981 
2982   {
2983     const PetscInt numCorners  = 3;
2984     const PetscInt numCells    = out.numberoftriangles;
2985     const PetscInt numVertices = out.numberofpoints;
2986     const int     *cells      = out.trianglelist;
2987     const double  *meshCoords = out.pointlist;
2988     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
2989 
2990     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
2991     /* Set labels */
2992     for (v = 0; v < numVertices; ++v) {
2993       if (out.pointmarkerlist[v]) {
2994         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
2995       }
2996     }
2997     if (interpolate) {
2998       PetscInt e;
2999 
3000       for (e = 0; e < out.numberofedges; e++) {
3001         if (out.edgemarkerlist[e]) {
3002           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3003           const PetscInt *edges;
3004           PetscInt        numEdges;
3005 
3006           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3007           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3008           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3009           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3010         }
3011       }
3012     }
3013     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3014   }
3015 #if 0 /* Do not currently support holes */
3016   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3017 #endif
3018   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3019   PetscFunctionReturn(0);
3020 }
3021 #endif
3022 
3023 #if defined(PETSC_HAVE_TETGEN)
3024 #include <tetgen.h>
3025 #undef __FUNCT__
3026 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3027 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3028 {
3029   MPI_Comm       comm;
3030   const PetscInt dim  = 3;
3031   ::tetgenio     in;
3032   ::tetgenio     out;
3033   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3034   PetscMPIInt    rank;
3035   PetscErrorCode ierr;
3036 
3037   PetscFunctionBegin;
3038   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3039   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3040   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3041   in.numberofpoints = vEnd - vStart;
3042   if (in.numberofpoints > 0) {
3043     PetscSection coordSection;
3044     Vec          coordinates;
3045     PetscScalar *array;
3046 
3047     in.pointlist       = new double[in.numberofpoints*dim];
3048     in.pointmarkerlist = new int[in.numberofpoints];
3049 
3050     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3051     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3052     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3053     for (v = vStart; v < vEnd; ++v) {
3054       const PetscInt idx = v - vStart;
3055       PetscInt       off, d;
3056 
3057       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3058       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3059       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3060     }
3061     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3062   }
3063   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3064 
3065   in.numberoffacets = fEnd - fStart;
3066   if (in.numberoffacets > 0) {
3067     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3068     in.facetmarkerlist = new int[in.numberoffacets];
3069     for (f = fStart; f < fEnd; ++f) {
3070       const PetscInt idx     = f - fStart;
3071       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3072 
3073       in.facetlist[idx].numberofpolygons = 1;
3074       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3075       in.facetlist[idx].numberofholes    = 0;
3076       in.facetlist[idx].holelist         = NULL;
3077 
3078       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3079       for (p = 0; p < numPoints*2; p += 2) {
3080         const PetscInt point = points[p];
3081         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3082       }
3083 
3084       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3085       poly->numberofvertices = numVertices;
3086       poly->vertexlist       = new int[poly->numberofvertices];
3087       for (v = 0; v < numVertices; ++v) {
3088         const PetscInt vIdx = points[v] - vStart;
3089         poly->vertexlist[v] = vIdx;
3090       }
3091       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3092       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3093     }
3094   }
3095   if (!rank) {
3096     char args[32];
3097 
3098     /* Take away 'Q' for verbose output */
3099     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3100     ::tetrahedralize(args, &in, &out);
3101   }
3102   {
3103     const PetscInt numCorners  = 4;
3104     const PetscInt numCells    = out.numberoftetrahedra;
3105     const PetscInt numVertices = out.numberofpoints;
3106     const double   *meshCoords = out.pointlist;
3107     int            *cells      = out.tetrahedronlist;
3108 
3109     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3110     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3111     /* Set labels */
3112     for (v = 0; v < numVertices; ++v) {
3113       if (out.pointmarkerlist[v]) {
3114         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3115       }
3116     }
3117     if (interpolate) {
3118       PetscInt e;
3119 
3120       for (e = 0; e < out.numberofedges; e++) {
3121         if (out.edgemarkerlist[e]) {
3122           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3123           const PetscInt *edges;
3124           PetscInt        numEdges;
3125 
3126           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3127           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3128           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3129           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3130         }
3131       }
3132       for (f = 0; f < out.numberoftrifaces; f++) {
3133         if (out.trifacemarkerlist[f]) {
3134           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3135           const PetscInt *faces;
3136           PetscInt        numFaces;
3137 
3138           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3139           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3140           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3141           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3142         }
3143       }
3144     }
3145     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3146   }
3147   PetscFunctionReturn(0);
3148 }
3149 
3150 #undef __FUNCT__
3151 #define __FUNCT__ "DMPlexRefine_Tetgen"
3152 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3153 {
3154   MPI_Comm       comm;
3155   const PetscInt dim  = 3;
3156   ::tetgenio     in;
3157   ::tetgenio     out;
3158   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3159   PetscMPIInt    rank;
3160   PetscErrorCode ierr;
3161 
3162   PetscFunctionBegin;
3163   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3164   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3165   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3166   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3167   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3168 
3169   in.numberofpoints = vEnd - vStart;
3170   if (in.numberofpoints > 0) {
3171     PetscSection coordSection;
3172     Vec          coordinates;
3173     PetscScalar *array;
3174 
3175     in.pointlist       = new double[in.numberofpoints*dim];
3176     in.pointmarkerlist = new int[in.numberofpoints];
3177 
3178     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3179     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3180     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3181     for (v = vStart; v < vEnd; ++v) {
3182       const PetscInt idx = v - vStart;
3183       PetscInt       off, d;
3184 
3185       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3186       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3187       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3188     }
3189     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3190   }
3191   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3192 
3193   in.numberofcorners       = 4;
3194   in.numberoftetrahedra    = cEnd - cStart;
3195   in.tetrahedronvolumelist = (double*) maxVolumes;
3196   if (in.numberoftetrahedra > 0) {
3197     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3198     for (c = cStart; c < cEnd; ++c) {
3199       const PetscInt idx      = c - cStart;
3200       PetscInt      *closure = NULL;
3201       PetscInt       closureSize;
3202 
3203       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3204       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3205       for (v = 0; v < 4; ++v) {
3206         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3207       }
3208       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3209     }
3210   }
3211   /* TODO: Put in boundary faces with markers */
3212   if (!rank) {
3213     char args[32];
3214 
3215     /* Take away 'Q' for verbose output */
3216     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3217     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3218     ::tetrahedralize(args, &in, &out);
3219   }
3220   in.tetrahedronvolumelist = NULL;
3221 
3222   {
3223     const PetscInt numCorners  = 4;
3224     const PetscInt numCells    = out.numberoftetrahedra;
3225     const PetscInt numVertices = out.numberofpoints;
3226     const double   *meshCoords = out.pointlist;
3227     int            *cells      = out.tetrahedronlist;
3228 
3229     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3230 
3231     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3232     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3233     /* Set labels */
3234     for (v = 0; v < numVertices; ++v) {
3235       if (out.pointmarkerlist[v]) {
3236         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3237       }
3238     }
3239     if (interpolate) {
3240       PetscInt e, f;
3241 
3242       for (e = 0; e < out.numberofedges; e++) {
3243         if (out.edgemarkerlist[e]) {
3244           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3245           const PetscInt *edges;
3246           PetscInt        numEdges;
3247 
3248           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3249           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3250           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3251           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3252         }
3253       }
3254       for (f = 0; f < out.numberoftrifaces; f++) {
3255         if (out.trifacemarkerlist[f]) {
3256           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3257           const PetscInt *faces;
3258           PetscInt        numFaces;
3259 
3260           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3261           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3262           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3263           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3264         }
3265       }
3266     }
3267     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3268   }
3269   PetscFunctionReturn(0);
3270 }
3271 #endif
3272 
3273 #if defined(PETSC_HAVE_CTETGEN)
3274 #include <ctetgen.h>
3275 
3276 #undef __FUNCT__
3277 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3278 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3279 {
3280   MPI_Comm       comm;
3281   const PetscInt dim  = 3;
3282   PLC           *in, *out;
3283   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3284   PetscMPIInt    rank;
3285   PetscErrorCode ierr;
3286 
3287   PetscFunctionBegin;
3288   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3289   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3290   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3291   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3292   ierr = PLCCreate(&in);CHKERRQ(ierr);
3293   ierr = PLCCreate(&out);CHKERRQ(ierr);
3294 
3295   in->numberofpoints = vEnd - vStart;
3296   if (in->numberofpoints > 0) {
3297     PetscSection coordSection;
3298     Vec          coordinates;
3299     PetscScalar *array;
3300 
3301     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
3302     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
3303     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3304     ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3305     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3306     for (v = vStart; v < vEnd; ++v) {
3307       const PetscInt idx = v - vStart;
3308       PetscInt       off, d, m;
3309 
3310       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3311       for (d = 0; d < dim; ++d) {
3312         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3313       }
3314       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3315 
3316       in->pointmarkerlist[idx] = (int) m;
3317     }
3318     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3319   }
3320   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3321 
3322   in->numberoffacets = fEnd - fStart;
3323   if (in->numberoffacets > 0) {
3324     ierr = PetscMalloc1(in->numberoffacets, &in->facetlist);CHKERRQ(ierr);
3325     ierr = PetscMalloc1(in->numberoffacets,   &in->facetmarkerlist);CHKERRQ(ierr);
3326     for (f = fStart; f < fEnd; ++f) {
3327       const PetscInt idx     = f - fStart;
3328       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3329       polygon       *poly;
3330 
3331       in->facetlist[idx].numberofpolygons = 1;
3332 
3333       ierr = PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3334 
3335       in->facetlist[idx].numberofholes    = 0;
3336       in->facetlist[idx].holelist         = NULL;
3337 
3338       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3339       for (p = 0; p < numPoints*2; p += 2) {
3340         const PetscInt point = points[p];
3341         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3342       }
3343 
3344       poly                   = in->facetlist[idx].polygonlist;
3345       poly->numberofvertices = numVertices;
3346       ierr                   = PetscMalloc1(poly->numberofvertices, &poly->vertexlist);CHKERRQ(ierr);
3347       for (v = 0; v < numVertices; ++v) {
3348         const PetscInt vIdx = points[v] - vStart;
3349         poly->vertexlist[v] = vIdx;
3350       }
3351       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3352       in->facetmarkerlist[idx] = (int) m;
3353       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3354     }
3355   }
3356   if (!rank) {
3357     TetGenOpts t;
3358 
3359     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3360     t.in        = boundary; /* Should go away */
3361     t.plc       = 1;
3362     t.quality   = 1;
3363     t.edgesout  = 1;
3364     t.zeroindex = 1;
3365     t.quiet     = 1;
3366     t.verbose   = verbose;
3367     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3368     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3369   }
3370   {
3371     const PetscInt numCorners  = 4;
3372     const PetscInt numCells    = out->numberoftetrahedra;
3373     const PetscInt numVertices = out->numberofpoints;
3374     const double   *meshCoords = out->pointlist;
3375     int            *cells      = out->tetrahedronlist;
3376 
3377     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3378     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3379     /* Set labels */
3380     for (v = 0; v < numVertices; ++v) {
3381       if (out->pointmarkerlist[v]) {
3382         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3383       }
3384     }
3385     if (interpolate) {
3386       PetscInt e;
3387 
3388       for (e = 0; e < out->numberofedges; e++) {
3389         if (out->edgemarkerlist[e]) {
3390           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3391           const PetscInt *edges;
3392           PetscInt        numEdges;
3393 
3394           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3395           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3396           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3397           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3398         }
3399       }
3400       for (f = 0; f < out->numberoftrifaces; f++) {
3401         if (out->trifacemarkerlist[f]) {
3402           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3403           const PetscInt *faces;
3404           PetscInt        numFaces;
3405 
3406           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3407           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3408           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3409           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3410         }
3411       }
3412     }
3413     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3414   }
3415 
3416   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3417   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3418   PetscFunctionReturn(0);
3419 }
3420 
3421 #undef __FUNCT__
3422 #define __FUNCT__ "DMPlexRefine_CTetgen"
3423 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3424 {
3425   MPI_Comm       comm;
3426   const PetscInt dim  = 3;
3427   PLC           *in, *out;
3428   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3429   PetscMPIInt    rank;
3430   PetscErrorCode ierr;
3431 
3432   PetscFunctionBegin;
3433   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3434   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3435   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3436   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3437   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3438   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3439   ierr = PLCCreate(&in);CHKERRQ(ierr);
3440   ierr = PLCCreate(&out);CHKERRQ(ierr);
3441 
3442   in->numberofpoints = vEnd - vStart;
3443   if (in->numberofpoints > 0) {
3444     PetscSection coordSection;
3445     Vec          coordinates;
3446     PetscScalar *array;
3447 
3448     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
3449     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
3450     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3451     ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3452     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3453     for (v = vStart; v < vEnd; ++v) {
3454       const PetscInt idx = v - vStart;
3455       PetscInt       off, d, m;
3456 
3457       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3458       for (d = 0; d < dim; ++d) {
3459         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3460       }
3461       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3462 
3463       in->pointmarkerlist[idx] = (int) m;
3464     }
3465     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3466   }
3467   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3468 
3469   in->numberofcorners       = 4;
3470   in->numberoftetrahedra    = cEnd - cStart;
3471   in->tetrahedronvolumelist = maxVolumes;
3472   if (in->numberoftetrahedra > 0) {
3473     ierr = PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);CHKERRQ(ierr);
3474     for (c = cStart; c < cEnd; ++c) {
3475       const PetscInt idx      = c - cStart;
3476       PetscInt      *closure = NULL;
3477       PetscInt       closureSize;
3478 
3479       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3480       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3481       for (v = 0; v < 4; ++v) {
3482         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3483       }
3484       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3485     }
3486   }
3487   if (!rank) {
3488     TetGenOpts t;
3489 
3490     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3491 
3492     t.in        = dm; /* Should go away */
3493     t.refine    = 1;
3494     t.varvolume = 1;
3495     t.quality   = 1;
3496     t.edgesout  = 1;
3497     t.zeroindex = 1;
3498     t.quiet     = 1;
3499     t.verbose   = verbose; /* Change this */
3500 
3501     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3502     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3503   }
3504   {
3505     const PetscInt numCorners  = 4;
3506     const PetscInt numCells    = out->numberoftetrahedra;
3507     const PetscInt numVertices = out->numberofpoints;
3508     const double   *meshCoords = out->pointlist;
3509     int            *cells      = out->tetrahedronlist;
3510     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3511 
3512     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3513     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3514     /* Set labels */
3515     for (v = 0; v < numVertices; ++v) {
3516       if (out->pointmarkerlist[v]) {
3517         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3518       }
3519     }
3520     if (interpolate) {
3521       PetscInt e, f;
3522 
3523       for (e = 0; e < out->numberofedges; e++) {
3524         if (out->edgemarkerlist[e]) {
3525           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3526           const PetscInt *edges;
3527           PetscInt        numEdges;
3528 
3529           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3530           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3531           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3532           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3533         }
3534       }
3535       for (f = 0; f < out->numberoftrifaces; f++) {
3536         if (out->trifacemarkerlist[f]) {
3537           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3538           const PetscInt *faces;
3539           PetscInt        numFaces;
3540 
3541           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3542           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3543           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3544           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3545         }
3546       }
3547     }
3548     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3549   }
3550   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3551   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3552   PetscFunctionReturn(0);
3553 }
3554 #endif
3555 
3556 #undef __FUNCT__
3557 #define __FUNCT__ "DMPlexGenerate"
3558 /*@C
3559   DMPlexGenerate - Generates a mesh.
3560 
3561   Not Collective
3562 
3563   Input Parameters:
3564 + boundary - The DMPlex boundary object
3565 . name - The mesh generation package name
3566 - interpolate - Flag to create intermediate mesh elements
3567 
3568   Output Parameter:
3569 . mesh - The DMPlex object
3570 
3571   Level: intermediate
3572 
3573 .keywords: mesh, elements
3574 .seealso: DMPlexCreate(), DMRefine()
3575 @*/
3576 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3577 {
3578   PetscInt       dim;
3579   char           genname[1024];
3580   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
3581   PetscErrorCode ierr;
3582 
3583   PetscFunctionBegin;
3584   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
3585   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
3586   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
3587   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
3588   if (flg) name = genname;
3589   if (name) {
3590     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
3591     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
3592     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
3593   }
3594   switch (dim) {
3595   case 1:
3596     if (!name || isTriangle) {
3597 #if defined(PETSC_HAVE_TRIANGLE)
3598       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
3599 #else
3600       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
3601 #endif
3602     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
3603     break;
3604   case 2:
3605     if (!name || isCTetgen) {
3606 #if defined(PETSC_HAVE_CTETGEN)
3607       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3608 #else
3609       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
3610 #endif
3611     } else if (isTetgen) {
3612 #if defined(PETSC_HAVE_TETGEN)
3613       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3614 #else
3615       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
3616 #endif
3617     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
3618     break;
3619   default:
3620     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
3621   }
3622   PetscFunctionReturn(0);
3623 }
3624 
3625 #undef __FUNCT__
3626 #define __FUNCT__ "DMRefine_Plex"
3627 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
3628 {
3629   PetscReal      refinementLimit;
3630   PetscInt       dim, cStart, cEnd;
3631   char           genname[1024], *name = NULL;
3632   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
3633   PetscErrorCode ierr;
3634 
3635   PetscFunctionBegin;
3636   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
3637   if (isUniform) {
3638     CellRefiner cellRefiner;
3639 
3640     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
3641     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
3642     PetscFunctionReturn(0);
3643   }
3644   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
3645   if (refinementLimit == 0.0) PetscFunctionReturn(0);
3646   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3647   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3648   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
3649   if (flg) name = genname;
3650   if (name) {
3651     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
3652     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
3653     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
3654   }
3655   switch (dim) {
3656   case 2:
3657     if (!name || isTriangle) {
3658 #if defined(PETSC_HAVE_TRIANGLE)
3659       double  *maxVolumes;
3660       PetscInt c;
3661 
3662       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
3663       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
3664       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
3665       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
3666 #else
3667       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
3668 #endif
3669     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
3670     break;
3671   case 3:
3672     if (!name || isCTetgen) {
3673 #if defined(PETSC_HAVE_CTETGEN)
3674       PetscReal *maxVolumes;
3675       PetscInt   c;
3676 
3677       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
3678       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
3679       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
3680 #else
3681       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
3682 #endif
3683     } else if (isTetgen) {
3684 #if defined(PETSC_HAVE_TETGEN)
3685       double  *maxVolumes;
3686       PetscInt c;
3687 
3688       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
3689       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
3690       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
3691 #else
3692       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
3693 #endif
3694     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
3695     break;
3696   default:
3697     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
3698   }
3699   PetscFunctionReturn(0);
3700 }
3701 
3702 #undef __FUNCT__
3703 #define __FUNCT__ "DMRefineHierarchy_Plex"
3704 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
3705 {
3706   DM             cdm = dm;
3707   PetscInt       r;
3708   PetscBool      isUniform;
3709   PetscErrorCode ierr;
3710 
3711   PetscFunctionBegin;
3712   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
3713   if (!isUniform) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Non-uniform refinement is incompatible with the hierarchy");
3714   for (r = 0; r < nlevels; ++r) {
3715     CellRefiner cellRefiner;
3716 
3717     ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
3718     ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
3719     ierr = DMPlexSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
3720     cdm  = dmRefined[r];
3721   }
3722   PetscFunctionReturn(0);
3723 }
3724 
3725 #undef __FUNCT__
3726 #define __FUNCT__ "DMCoarsen_Plex"
3727 PetscErrorCode DMCoarsen_Plex(DM dm, MPI_Comm comm, DM *dmCoarsened)
3728 {
3729   DM_Plex       *mesh = (DM_Plex*) dm->data;
3730   PetscErrorCode ierr;
3731 
3732   PetscFunctionBegin;
3733   ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr);
3734   *dmCoarsened = mesh->coarseMesh;
3735   PetscFunctionReturn(0);
3736 }
3737 
3738 #undef __FUNCT__
3739 #define __FUNCT__ "DMPlexLocalizeCoordinate_Internal"
3740 PetscErrorCode DMPlexLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
3741 {
3742   PetscInt d;
3743 
3744   PetscFunctionBegin;
3745   if (!dm->maxCell) {
3746     for (d = 0; d < dim; ++d) out[d] = in[d];
3747   } else {
3748     for (d = 0; d < dim; ++d) {
3749       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
3750         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
3751       } else {
3752         out[d] = in[d];
3753       }
3754     }
3755   }
3756   PetscFunctionReturn(0);
3757 }
3758 
3759 #undef __FUNCT__
3760 #define __FUNCT__ "DMPlexLocalizeAddCoordinate_Internal"
3761 PetscErrorCode DMPlexLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
3762 {
3763   PetscInt d;
3764 
3765   PetscFunctionBegin;
3766   if (!dm->maxCell) {
3767     for (d = 0; d < dim; ++d) out[d] += in[d];
3768   } else {
3769     for (d = 0; d < dim; ++d) {
3770       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
3771         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
3772       } else {
3773         out[d] += in[d];
3774       }
3775     }
3776   }
3777   PetscFunctionReturn(0);
3778 }
3779 
3780 #undef __FUNCT__
3781 #define __FUNCT__ "DMPlexLocalizeCoordinates"
3782 PetscErrorCode DMPlexLocalizeCoordinates(DM dm)
3783 {
3784   PetscSection   coordSection, cSection;
3785   Vec            coordinates,  cVec;
3786   PetscScalar   *coords, *coords2, *anchor;
3787   PetscInt       cStart, cEnd, c, vStart, vEnd, v, dof, d, off, off2, bs, coordSize;
3788   PetscErrorCode ierr;
3789 
3790   PetscFunctionBegin;
3791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3792   if (!dm->maxCell) PetscFunctionReturn(0);
3793   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3794   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3795   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3796   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3797   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
3798   ierr = PetscSectionSetChart(cSection, cStart, vEnd);CHKERRQ(ierr);
3799   for (v = vStart; v < vEnd; ++v) {
3800     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3801     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
3802   }
3803   for (c = cStart; c < cEnd; ++c) {
3804     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, NULL);CHKERRQ(ierr);
3805     ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
3806   }
3807   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
3808   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
3809   ierr = VecCreate(PetscObjectComm((PetscObject) dm), &cVec);CHKERRQ(ierr);
3810   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
3811   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
3812   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3813   ierr = VecSetType(cVec,VECSTANDARD);CHKERRQ(ierr);
3814   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3815   ierr = VecGetArray(cVec,        &coords2);CHKERRQ(ierr);
3816   for (v = vStart; v < vEnd; ++v) {
3817     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3818     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3819     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
3820     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
3821   }
3822   ierr = DMGetWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
3823   for (c = cStart; c < cEnd; ++c) {
3824     PetscScalar *cellCoords = NULL;
3825     PetscInt     b;
3826 
3827     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
3828     ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
3829     for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
3830     for (d = 0; d < dof/bs; ++d) {ierr = DMPlexLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
3831     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
3832   }
3833   ierr = DMRestoreWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
3834   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3835   ierr = VecRestoreArray(cVec,        &coords2);CHKERRQ(ierr);
3836   ierr = DMSetCoordinateSection(dm, cSection);CHKERRQ(ierr);
3837   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
3838   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
3839   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
3840   PetscFunctionReturn(0);
3841 }
3842 
3843 #undef __FUNCT__
3844 #define __FUNCT__ "DMPlexGetDepthLabel"
3845 /*@
3846   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3847 
3848   Not Collective
3849 
3850   Input Parameter:
3851 . dm    - The DMPlex object
3852 
3853   Output Parameter:
3854 . depthLabel - The DMLabel recording point depth
3855 
3856   Level: developer
3857 
3858 .keywords: mesh, points
3859 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3860 @*/
3861 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3862 {
3863   DM_Plex       *mesh = (DM_Plex*) dm->data;
3864   PetscErrorCode ierr;
3865 
3866   PetscFunctionBegin;
3867   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3868   PetscValidPointer(depthLabel, 2);
3869   if (!mesh->depthLabel) {ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);}
3870   *depthLabel = mesh->depthLabel;
3871   PetscFunctionReturn(0);
3872 }
3873 
3874 #undef __FUNCT__
3875 #define __FUNCT__ "DMPlexGetDepth"
3876 /*@
3877   DMPlexGetDepth - Get the depth of the DAG representing this mesh
3878 
3879   Not Collective
3880 
3881   Input Parameter:
3882 . dm    - The DMPlex object
3883 
3884   Output Parameter:
3885 . depth - The number of strata (breadth first levels) in the DAG
3886 
3887   Level: developer
3888 
3889 .keywords: mesh, points
3890 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3891 @*/
3892 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3893 {
3894   DMLabel        label;
3895   PetscInt       d = 0;
3896   PetscErrorCode ierr;
3897 
3898   PetscFunctionBegin;
3899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3900   PetscValidPointer(depth, 2);
3901   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3902   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
3903   *depth = d-1;
3904   PetscFunctionReturn(0);
3905 }
3906 
3907 #undef __FUNCT__
3908 #define __FUNCT__ "DMPlexGetDepthStratum"
3909 /*@
3910   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3911 
3912   Not Collective
3913 
3914   Input Parameters:
3915 + dm           - The DMPlex object
3916 - stratumValue - The requested depth
3917 
3918   Output Parameters:
3919 + start - The first point at this depth
3920 - end   - One beyond the last point at this depth
3921 
3922   Level: developer
3923 
3924 .keywords: mesh, points
3925 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3926 @*/
3927 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3928 {
3929   DMLabel        label;
3930   PetscInt       pStart, pEnd;
3931   PetscErrorCode ierr;
3932 
3933   PetscFunctionBegin;
3934   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3935   if (start) {PetscValidPointer(start, 3); *start = 0;}
3936   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3937   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3938   if (pStart == pEnd) PetscFunctionReturn(0);
3939   if (stratumValue < 0) {
3940     if (start) *start = pStart;
3941     if (end)   *end   = pEnd;
3942     PetscFunctionReturn(0);
3943   }
3944   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3945   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3946   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
3947   PetscFunctionReturn(0);
3948 }
3949 
3950 #undef __FUNCT__
3951 #define __FUNCT__ "DMPlexGetHeightStratum"
3952 /*@
3953   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3954 
3955   Not Collective
3956 
3957   Input Parameters:
3958 + dm           - The DMPlex object
3959 - stratumValue - The requested height
3960 
3961   Output Parameters:
3962 + start - The first point at this height
3963 - end   - One beyond the last point at this height
3964 
3965   Level: developer
3966 
3967 .keywords: mesh, points
3968 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3969 @*/
3970 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3971 {
3972   DMLabel        label;
3973   PetscInt       depth, pStart, pEnd;
3974   PetscErrorCode ierr;
3975 
3976   PetscFunctionBegin;
3977   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3978   if (start) {PetscValidPointer(start, 3); *start = 0;}
3979   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3980   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3981   if (pStart == pEnd) PetscFunctionReturn(0);
3982   if (stratumValue < 0) {
3983     if (start) *start = pStart;
3984     if (end)   *end   = pEnd;
3985     PetscFunctionReturn(0);
3986   }
3987   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3988   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
3989   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
3990   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
3991   PetscFunctionReturn(0);
3992 }
3993 
3994 #undef __FUNCT__
3995 #define __FUNCT__ "DMPlexCreateSectionInitial"
3996 /* Set the number of dof on each point and separate by fields */
3997 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
3998 {
3999   PetscInt      *numDofTot;
4000   PetscInt       depth, pStart = 0, pEnd = 0;
4001   PetscInt       p, d, dep, f;
4002   PetscErrorCode ierr;
4003 
4004   PetscFunctionBegin;
4005   ierr = PetscMalloc1((dim+1), &numDofTot);CHKERRQ(ierr);
4006   for (d = 0; d <= dim; ++d) {
4007     numDofTot[d] = 0;
4008     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
4009   }
4010   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
4011   if (numFields > 0) {
4012     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
4013     if (numComp) {
4014       for (f = 0; f < numFields; ++f) {
4015         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
4016       }
4017     }
4018   }
4019   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4020   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
4021   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4022   for (dep = 0; dep <= depth; ++dep) {
4023     d    = dim == depth ? dep : (!dep ? 0 : dim);
4024     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
4025     for (p = pStart; p < pEnd; ++p) {
4026       for (f = 0; f < numFields; ++f) {
4027         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
4028       }
4029       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
4030     }
4031   }
4032   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
4033   PetscFunctionReturn(0);
4034 }
4035 
4036 #undef __FUNCT__
4037 #define __FUNCT__ "DMPlexCreateSectionBCDof"
4038 /* Set the number of dof on each point and separate by fields
4039    If constDof is PETSC_DETERMINE, constrain every dof on the point
4040 */
4041 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
4042 {
4043   PetscInt       numFields;
4044   PetscInt       bc;
4045   PetscErrorCode ierr;
4046 
4047   PetscFunctionBegin;
4048   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4049   for (bc = 0; bc < numBC; ++bc) {
4050     PetscInt        field = 0;
4051     const PetscInt *idx;
4052     PetscInt        n, i;
4053 
4054     if (numFields) field = bcField[bc];
4055     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
4056     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4057     for (i = 0; i < n; ++i) {
4058       const PetscInt p        = idx[i];
4059       PetscInt       numConst = constDof;
4060 
4061       /* Constrain every dof on the point */
4062       if (numConst < 0) {
4063         if (numFields) {
4064           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
4065         } else {
4066           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
4067         }
4068       }
4069       if (numFields) {
4070         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
4071       }
4072       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
4073     }
4074     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4075   }
4076   PetscFunctionReturn(0);
4077 }
4078 
4079 #undef __FUNCT__
4080 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
4081 /* Set the constrained indices on each point and separate by fields */
4082 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
4083 {
4084   PetscInt      *maxConstraints;
4085   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
4086   PetscErrorCode ierr;
4087 
4088   PetscFunctionBegin;
4089   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4090   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4091   ierr = PetscMalloc1((numFields+1), &maxConstraints);CHKERRQ(ierr);
4092   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
4093   for (p = pStart; p < pEnd; ++p) {
4094     PetscInt cdof;
4095 
4096     if (numFields) {
4097       for (f = 0; f < numFields; ++f) {
4098         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
4099         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
4100       }
4101     } else {
4102       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4103       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
4104     }
4105   }
4106   for (f = 0; f < numFields; ++f) {
4107     maxConstraints[numFields] += maxConstraints[f];
4108   }
4109   if (maxConstraints[numFields]) {
4110     PetscInt *indices;
4111 
4112     ierr = PetscMalloc1(maxConstraints[numFields], &indices);CHKERRQ(ierr);
4113     for (p = pStart; p < pEnd; ++p) {
4114       PetscInt cdof, d;
4115 
4116       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4117       if (cdof) {
4118         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
4119         if (numFields) {
4120           PetscInt numConst = 0, foff = 0;
4121 
4122           for (f = 0; f < numFields; ++f) {
4123             PetscInt cfdof, fdof;
4124 
4125             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4126             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
4127             /* Change constraint numbering from absolute local dof number to field relative local dof number */
4128             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
4129             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
4130             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
4131             numConst += cfdof;
4132             foff     += fdof;
4133           }
4134           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4135         } else {
4136           for (d = 0; d < cdof; ++d) indices[d] = d;
4137         }
4138         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4139       }
4140     }
4141     ierr = PetscFree(indices);CHKERRQ(ierr);
4142   }
4143   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
4144   PetscFunctionReturn(0);
4145 }
4146 
4147 #undef __FUNCT__
4148 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
4149 /* Set the constrained field indices on each point */
4150 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
4151 {
4152   const PetscInt *points, *indices;
4153   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
4154   PetscErrorCode  ierr;
4155 
4156   PetscFunctionBegin;
4157   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4158   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
4159 
4160   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
4161   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
4162   if (!constraintIndices) {
4163     PetscInt *idx, i;
4164 
4165     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4166     ierr = PetscMalloc1(maxDof, &idx);CHKERRQ(ierr);
4167     for (i = 0; i < maxDof; ++i) idx[i] = i;
4168     for (p = 0; p < numPoints; ++p) {
4169       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
4170     }
4171     ierr = PetscFree(idx);CHKERRQ(ierr);
4172   } else {
4173     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
4174     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
4175     for (p = 0; p < numPoints; ++p) {
4176       PetscInt fcdof;
4177 
4178       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
4179       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
4180       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
4181     }
4182     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
4183   }
4184   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
4185   PetscFunctionReturn(0);
4186 }
4187 
4188 #undef __FUNCT__
4189 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
4190 /* Set the constrained indices on each point and separate by fields */
4191 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
4192 {
4193   PetscInt      *indices;
4194   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
4195   PetscErrorCode ierr;
4196 
4197   PetscFunctionBegin;
4198   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4199   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
4200   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4201   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
4202   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4203   for (p = pStart; p < pEnd; ++p) {
4204     PetscInt cdof, d;
4205 
4206     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4207     if (cdof) {
4208       PetscInt numConst = 0, foff = 0;
4209 
4210       for (f = 0; f < numFields; ++f) {
4211         const PetscInt *fcind;
4212         PetscInt        fdof, fcdof;
4213 
4214         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4215         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
4216         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
4217         /* Change constraint numbering from field relative local dof number to absolute local dof number */
4218         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
4219         foff     += fdof;
4220         numConst += fcdof;
4221       }
4222       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4223       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4224     }
4225   }
4226   ierr = PetscFree(indices);CHKERRQ(ierr);
4227   PetscFunctionReturn(0);
4228 }
4229 
4230 #undef __FUNCT__
4231 #define __FUNCT__ "DMPlexCreateSection"
4232 /*@C
4233   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
4234 
4235   Not Collective
4236 
4237   Input Parameters:
4238 + dm        - The DMPlex object
4239 . dim       - The spatial dimension of the problem
4240 . numFields - The number of fields in the problem
4241 . numComp   - An array of size numFields that holds the number of components for each field
4242 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
4243 . numBC     - The number of boundary conditions
4244 . bcField   - An array of size numBC giving the field number for each boundry condition
4245 . bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
4246 - perm      - Optional permutation of the chart, or NULL
4247 
4248   Output Parameter:
4249 . section - The PetscSection object
4250 
4251   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
4252   number of dof for field 0 on each edge.
4253 
4254   The chart permutation is the same one set using PetscSectionSetPermutation()
4255 
4256   Level: developer
4257 
4258   Fortran Notes:
4259   A Fortran 90 version is available as DMPlexCreateSectionF90()
4260 
4261 .keywords: mesh, elements
4262 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
4263 @*/
4264 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], IS perm, PetscSection *section)
4265 {
4266   PetscErrorCode ierr;
4267 
4268   PetscFunctionBegin;
4269   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
4270   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
4271   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
4272   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
4273   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
4274   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
4275   PetscFunctionReturn(0);
4276 }
4277 
4278 #undef __FUNCT__
4279 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
4280 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4281 {
4282   PetscSection   section;
4283   PetscErrorCode ierr;
4284 
4285   PetscFunctionBegin;
4286   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4287   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4288   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
4289   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4290   PetscFunctionReturn(0);
4291 }
4292 
4293 #undef __FUNCT__
4294 #define __FUNCT__ "DMPlexGetConeSection"
4295 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4296 {
4297   DM_Plex *mesh = (DM_Plex*) dm->data;
4298 
4299   PetscFunctionBegin;
4300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4301   if (section) *section = mesh->coneSection;
4302   PetscFunctionReturn(0);
4303 }
4304 
4305 #undef __FUNCT__
4306 #define __FUNCT__ "DMPlexGetSupportSection"
4307 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4308 {
4309   DM_Plex *mesh = (DM_Plex*) dm->data;
4310 
4311   PetscFunctionBegin;
4312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4313   if (section) *section = mesh->supportSection;
4314   PetscFunctionReturn(0);
4315 }
4316 
4317 #undef __FUNCT__
4318 #define __FUNCT__ "DMPlexGetCones"
4319 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4320 {
4321   DM_Plex *mesh = (DM_Plex*) dm->data;
4322 
4323   PetscFunctionBegin;
4324   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4325   if (cones) *cones = mesh->cones;
4326   PetscFunctionReturn(0);
4327 }
4328 
4329 #undef __FUNCT__
4330 #define __FUNCT__ "DMPlexGetConeOrientations"
4331 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4332 {
4333   DM_Plex *mesh = (DM_Plex*) dm->data;
4334 
4335   PetscFunctionBegin;
4336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4337   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4338   PetscFunctionReturn(0);
4339 }
4340 
4341 /******************************** FEM Support **********************************/
4342 
4343 #undef __FUNCT__
4344 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static"
4345 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4346 {
4347   PetscScalar    *array, *vArray;
4348   const PetscInt *cone, *coneO;
4349   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4350   PetscErrorCode  ierr;
4351 
4352   PetscFunctionBeginHot;
4353   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4354   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4355   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4356   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4357   if (!values || !*values) {
4358     if ((point >= pStart) && (point < pEnd)) {
4359       PetscInt dof;
4360 
4361       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4362       size += dof;
4363     }
4364     for (p = 0; p < numPoints; ++p) {
4365       const PetscInt cp = cone[p];
4366       PetscInt       dof;
4367 
4368       if ((cp < pStart) || (cp >= pEnd)) continue;
4369       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4370       size += dof;
4371     }
4372     if (!values) {
4373       if (csize) *csize = size;
4374       PetscFunctionReturn(0);
4375     }
4376     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4377   } else {
4378     array = *values;
4379   }
4380   size = 0;
4381   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4382   if ((point >= pStart) && (point < pEnd)) {
4383     PetscInt     dof, off, d;
4384     PetscScalar *varr;
4385 
4386     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4387     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4388     varr = &vArray[off];
4389     for (d = 0; d < dof; ++d, ++offset) {
4390       array[offset] = varr[d];
4391     }
4392     size += dof;
4393   }
4394   for (p = 0; p < numPoints; ++p) {
4395     const PetscInt cp = cone[p];
4396     PetscInt       o  = coneO[p];
4397     PetscInt       dof, off, d;
4398     PetscScalar   *varr;
4399 
4400     if ((cp < pStart) || (cp >= pEnd)) continue;
4401     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4402     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4403     varr = &vArray[off];
4404     if (o >= 0) {
4405       for (d = 0; d < dof; ++d, ++offset) {
4406         array[offset] = varr[d];
4407       }
4408     } else {
4409       for (d = dof-1; d >= 0; --d, ++offset) {
4410         array[offset] = varr[d];
4411       }
4412     }
4413     size += dof;
4414   }
4415   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4416   if (!*values) {
4417     if (csize) *csize = size;
4418     *values = array;
4419   } else {
4420     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
4421     *csize = size;
4422   }
4423   PetscFunctionReturn(0);
4424 }
4425 
4426 #undef __FUNCT__
4427 #define __FUNCT__ "DMPlexVecGetClosure_Static"
4428 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4429 {
4430   PetscInt       offset = 0, p;
4431   PetscErrorCode ierr;
4432 
4433   PetscFunctionBeginHot;
4434   *size = 0;
4435   for (p = 0; p < numPoints*2; p += 2) {
4436     const PetscInt point = points[p];
4437     const PetscInt o     = points[p+1];
4438     PetscInt       dof, off, d;
4439     const PetscScalar *varr;
4440 
4441     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4442     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4443     varr = &vArray[off];
4444     if (o >= 0) {
4445       for (d = 0; d < dof; ++d, ++offset)    array[offset] = varr[d];
4446     } else {
4447       for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
4448     }
4449   }
4450   *size = offset;
4451   PetscFunctionReturn(0);
4452 }
4453 
4454 #undef __FUNCT__
4455 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static"
4456 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
4457 {
4458   PetscInt       offset = 0, f;
4459   PetscErrorCode ierr;
4460 
4461   PetscFunctionBeginHot;
4462   *size = 0;
4463   for (f = 0; f < numFields; ++f) {
4464     PetscInt fcomp, p;
4465 
4466     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4467     for (p = 0; p < numPoints*2; p += 2) {
4468       const PetscInt point = points[p];
4469       const PetscInt o     = points[p+1];
4470       PetscInt       fdof, foff, d, c;
4471       const PetscScalar *varr;
4472 
4473       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4474       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4475       varr = &vArray[foff];
4476       if (o >= 0) {
4477         for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
4478       } else {
4479         for (d = fdof/fcomp-1; d >= 0; --d) {
4480           for (c = 0; c < fcomp; ++c, ++offset) {
4481             array[offset] = varr[d*fcomp+c];
4482           }
4483         }
4484       }
4485     }
4486   }
4487   *size = offset;
4488   PetscFunctionReturn(0);
4489 }
4490 
4491 #undef __FUNCT__
4492 #define __FUNCT__ "DMPlexVecGetClosure"
4493 /*@C
4494   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4495 
4496   Not collective
4497 
4498   Input Parameters:
4499 + dm - The DM
4500 . section - The section describing the layout in v, or NULL to use the default section
4501 . v - The local vector
4502 - point - The sieve point in the DM
4503 
4504   Output Parameters:
4505 + csize - The number of values in the closure, or NULL
4506 - values - The array of values, which is a borrowed array and should not be freed
4507 
4508   Fortran Notes:
4509   Since it returns an array, this routine is only available in Fortran 90, and you must
4510   include petsc.h90 in your code.
4511 
4512   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4513 
4514   Level: intermediate
4515 
4516 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4517 @*/
4518 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4519 {
4520   PetscSection    clSection;
4521   IS              clPoints;
4522   PetscScalar    *array, *vArray;
4523   PetscInt       *points = NULL;
4524   const PetscInt *clp;
4525   PetscInt        depth, numFields, numPoints, size;
4526   PetscErrorCode  ierr;
4527 
4528   PetscFunctionBeginHot;
4529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4530   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4531   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4532   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4533   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4534   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4535   if (depth == 1 && numFields < 2) {
4536     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
4537     PetscFunctionReturn(0);
4538   }
4539   /* Get points */
4540   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4541   if (!clPoints) {
4542     PetscInt pStart, pEnd, p, q;
4543 
4544     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4545     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4546     /* Compress out points not in the section */
4547     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4548       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4549         points[q*2]   = points[p];
4550         points[q*2+1] = points[p+1];
4551         ++q;
4552       }
4553     }
4554     numPoints = q;
4555   } else {
4556     PetscInt dof, off;
4557 
4558     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4559     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4560     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4561     numPoints = dof/2;
4562     points    = (PetscInt *) &clp[off];
4563   }
4564   /* Get array */
4565   if (!values || !*values) {
4566     PetscInt asize = 0, dof, p;
4567 
4568     for (p = 0; p < numPoints*2; p += 2) {
4569       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4570       asize += dof;
4571     }
4572     if (!values) {
4573       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4574       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4575       if (csize) *csize = asize;
4576       PetscFunctionReturn(0);
4577     }
4578     ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr);
4579   } else {
4580     array = *values;
4581   }
4582   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4583   /* Get values */
4584   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);CHKERRQ(ierr);}
4585   else               {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);CHKERRQ(ierr);}
4586   /* Cleanup points */
4587   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4588   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4589   /* Cleanup array */
4590   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4591   if (!*values) {
4592     if (csize) *csize = size;
4593     *values = array;
4594   } else {
4595     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
4596     *csize = size;
4597   }
4598   PetscFunctionReturn(0);
4599 }
4600 
4601 #undef __FUNCT__
4602 #define __FUNCT__ "DMPlexVecRestoreClosure"
4603 /*@C
4604   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4605 
4606   Not collective
4607 
4608   Input Parameters:
4609 + dm - The DM
4610 . section - The section describing the layout in v, or NULL to use the default section
4611 . v - The local vector
4612 . point - The sieve point in the DM
4613 . csize - The number of values in the closure, or NULL
4614 - values - The array of values, which is a borrowed array and should not be freed
4615 
4616   Fortran Notes:
4617   Since it returns an array, this routine is only available in Fortran 90, and you must
4618   include petsc.h90 in your code.
4619 
4620   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4621 
4622   Level: intermediate
4623 
4624 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4625 @*/
4626 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4627 {
4628   PetscInt       size = 0;
4629   PetscErrorCode ierr;
4630 
4631   PetscFunctionBegin;
4632   /* Should work without recalculating size */
4633   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
4634   PetscFunctionReturn(0);
4635 }
4636 
4637 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4638 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4639 
4640 #undef __FUNCT__
4641 #define __FUNCT__ "updatePoint_private"
4642 PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
4643 {
4644   PetscInt        cdof;   /* The number of constraints on this point */
4645   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4646   PetscScalar    *a;
4647   PetscInt        off, cind = 0, k;
4648   PetscErrorCode  ierr;
4649 
4650   PetscFunctionBegin;
4651   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4652   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4653   a    = &array[off];
4654   if (!cdof || setBC) {
4655     if (orientation >= 0) {
4656       for (k = 0; k < dof; ++k) {
4657         fuse(&a[k], values[k]);
4658       }
4659     } else {
4660       for (k = 0; k < dof; ++k) {
4661         fuse(&a[k], values[dof-k-1]);
4662       }
4663     }
4664   } else {
4665     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4666     if (orientation >= 0) {
4667       for (k = 0; k < dof; ++k) {
4668         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4669         fuse(&a[k], values[k]);
4670       }
4671     } else {
4672       for (k = 0; k < dof; ++k) {
4673         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4674         fuse(&a[k], values[dof-k-1]);
4675       }
4676     }
4677   }
4678   PetscFunctionReturn(0);
4679 }
4680 
4681 #undef __FUNCT__
4682 #define __FUNCT__ "updatePointBC_private"
4683 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
4684 {
4685   PetscInt        cdof;   /* The number of constraints on this point */
4686   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4687   PetscScalar    *a;
4688   PetscInt        off, cind = 0, k;
4689   PetscErrorCode  ierr;
4690 
4691   PetscFunctionBegin;
4692   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4693   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4694   a    = &array[off];
4695   if (cdof) {
4696     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4697     if (orientation >= 0) {
4698       for (k = 0; k < dof; ++k) {
4699         if ((cind < cdof) && (k == cdofs[cind])) {
4700           fuse(&a[k], values[k]);
4701           ++cind;
4702         }
4703       }
4704     } else {
4705       for (k = 0; k < dof; ++k) {
4706         if ((cind < cdof) && (k == cdofs[cind])) {
4707           fuse(&a[k], values[dof-k-1]);
4708           ++cind;
4709         }
4710       }
4711     }
4712   }
4713   PetscFunctionReturn(0);
4714 }
4715 
4716 #undef __FUNCT__
4717 #define __FUNCT__ "updatePointFields_private"
4718 PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4719 {
4720   PetscScalar    *a;
4721   PetscInt        fdof, foff, fcdof, foffset = *offset;
4722   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4723   PetscInt        cind = 0, k, c;
4724   PetscErrorCode  ierr;
4725 
4726   PetscFunctionBegin;
4727   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4728   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4729   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4730   a    = &array[foff];
4731   if (!fcdof || setBC) {
4732     if (o >= 0) {
4733       for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
4734     } else {
4735       for (k = fdof/fcomp-1; k >= 0; --k) {
4736         for (c = 0; c < fcomp; ++c) {
4737           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
4738         }
4739       }
4740     }
4741   } else {
4742     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4743     if (o >= 0) {
4744       for (k = 0; k < fdof; ++k) {
4745         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
4746         fuse(&a[k], values[foffset+k]);
4747       }
4748     } else {
4749       for (k = fdof/fcomp-1; k >= 0; --k) {
4750         for (c = 0; c < fcomp; ++c) {
4751           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
4752           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
4753         }
4754       }
4755     }
4756   }
4757   *offset += fdof;
4758   PetscFunctionReturn(0);
4759 }
4760 
4761 #undef __FUNCT__
4762 #define __FUNCT__ "updatePointFieldsBC_private"
4763 PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscScalar values[], PetscInt *offset, PetscScalar array[])
4764 {
4765   PetscScalar    *a;
4766   PetscInt        fdof, foff, fcdof, foffset = *offset;
4767   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4768   PetscInt        cind = 0, k, c;
4769   PetscErrorCode  ierr;
4770 
4771   PetscFunctionBegin;
4772   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4773   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4774   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4775   a    = &array[foff];
4776   if (fcdof) {
4777     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4778     if (o >= 0) {
4779       for (k = 0; k < fdof; ++k) {
4780         if ((cind < fcdof) && (k == fcdofs[cind])) {
4781           fuse(&a[k], values[foffset+k]);
4782           ++cind;
4783         }
4784       }
4785     } else {
4786       for (k = fdof/fcomp-1; k >= 0; --k) {
4787         for (c = 0; c < fcomp; ++c) {
4788           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
4789             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
4790             ++cind;
4791           }
4792         }
4793       }
4794     }
4795   }
4796   *offset += fdof;
4797   PetscFunctionReturn(0);
4798 }
4799 
4800 #undef __FUNCT__
4801 #define __FUNCT__ "DMPlexVecSetClosure_Static"
4802 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4803 {
4804   PetscScalar    *array;
4805   const PetscInt *cone, *coneO;
4806   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4807   PetscErrorCode  ierr;
4808 
4809   PetscFunctionBeginHot;
4810   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4811   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4812   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4813   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4814   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4815   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4816     const PetscInt cp = !p ? point : cone[p-1];
4817     const PetscInt o  = !p ? 0     : coneO[p-1];
4818 
4819     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4820     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4821     /* ADD_VALUES */
4822     {
4823       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4824       PetscScalar    *a;
4825       PetscInt        cdof, coff, cind = 0, k;
4826 
4827       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
4828       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
4829       a    = &array[coff];
4830       if (!cdof) {
4831         if (o >= 0) {
4832           for (k = 0; k < dof; ++k) {
4833             a[k] += values[off+k];
4834           }
4835         } else {
4836           for (k = 0; k < dof; ++k) {
4837             a[k] += values[off+dof-k-1];
4838           }
4839         }
4840       } else {
4841         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
4842         if (o >= 0) {
4843           for (k = 0; k < dof; ++k) {
4844             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4845             a[k] += values[off+k];
4846           }
4847         } else {
4848           for (k = 0; k < dof; ++k) {
4849             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4850             a[k] += values[off+dof-k-1];
4851           }
4852         }
4853       }
4854     }
4855   }
4856   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4857   PetscFunctionReturn(0);
4858 }
4859 
4860 #undef __FUNCT__
4861 #define __FUNCT__ "DMPlexVecSetClosure"
4862 /*@C
4863   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4864 
4865   Not collective
4866 
4867   Input Parameters:
4868 + dm - The DM
4869 . section - The section describing the layout in v, or NULL to use the default section
4870 . v - The local vector
4871 . point - The sieve point in the DM
4872 . values - The array of values
4873 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4874 
4875   Fortran Notes:
4876   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4877 
4878   Level: intermediate
4879 
4880 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4881 @*/
4882 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4883 {
4884   PetscSection    clSection;
4885   IS              clPoints;
4886   PetscScalar    *array;
4887   PetscInt       *points = NULL;
4888   const PetscInt *clp;
4889   PetscInt        depth, numFields, numPoints, p;
4890   PetscErrorCode  ierr;
4891 
4892   PetscFunctionBeginHot;
4893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4894   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4895   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4896   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4897   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4898   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4899   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4900     ierr = DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
4901     PetscFunctionReturn(0);
4902   }
4903   /* Get points */
4904   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4905   if (!clPoints) {
4906     PetscInt pStart, pEnd, q;
4907 
4908     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4909     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4910     /* Compress out points not in the section */
4911     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4912       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4913         points[q*2]   = points[p];
4914         points[q*2+1] = points[p+1];
4915         ++q;
4916       }
4917     }
4918     numPoints = q;
4919   } else {
4920     PetscInt dof, off;
4921 
4922     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4923     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4924     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4925     numPoints = dof/2;
4926     points    = (PetscInt *) &clp[off];
4927   }
4928   /* Get array */
4929   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4930   /* Get values */
4931   if (numFields > 0) {
4932     PetscInt offset = 0, fcomp, f;
4933     for (f = 0; f < numFields; ++f) {
4934       ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4935       switch (mode) {
4936       case INSERT_VALUES:
4937         for (p = 0; p < numPoints*2; p += 2) {
4938           const PetscInt point = points[p];
4939           const PetscInt o     = points[p+1];
4940           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
4941         } break;
4942       case INSERT_ALL_VALUES:
4943         for (p = 0; p < numPoints*2; p += 2) {
4944           const PetscInt point = points[p];
4945           const PetscInt o     = points[p+1];
4946           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
4947         } break;
4948       case INSERT_BC_VALUES:
4949         for (p = 0; p < numPoints*2; p += 2) {
4950           const PetscInt point = points[p];
4951           const PetscInt o     = points[p+1];
4952           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
4953         } break;
4954       case ADD_VALUES:
4955         for (p = 0; p < numPoints*2; p += 2) {
4956           const PetscInt point = points[p];
4957           const PetscInt o     = points[p+1];
4958           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
4959         } break;
4960       case ADD_ALL_VALUES:
4961         for (p = 0; p < numPoints*2; p += 2) {
4962           const PetscInt point = points[p];
4963           const PetscInt o     = points[p+1];
4964           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
4965         } break;
4966       default:
4967         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
4968       }
4969     }
4970   } else {
4971     PetscInt dof, off;
4972 
4973     switch (mode) {
4974     case INSERT_VALUES:
4975       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4976         PetscInt o = points[p+1];
4977         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4978         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
4979       } break;
4980     case INSERT_ALL_VALUES:
4981       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4982         PetscInt o = points[p+1];
4983         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4984         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
4985       } break;
4986     case INSERT_BC_VALUES:
4987       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4988         PetscInt o = points[p+1];
4989         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4990         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
4991       } break;
4992     case ADD_VALUES:
4993       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4994         PetscInt o = points[p+1];
4995         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4996         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
4997       } break;
4998     case ADD_ALL_VALUES:
4999       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5000         PetscInt o = points[p+1];
5001         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5002         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
5003       } break;
5004     default:
5005       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5006     }
5007   }
5008   /* Cleanup points */
5009   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
5010   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
5011   /* Cleanup array */
5012   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5013   PetscFunctionReturn(0);
5014 }
5015 
5016 #undef __FUNCT__
5017 #define __FUNCT__ "DMPlexPrintMatSetValues"
5018 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5019 {
5020   PetscMPIInt    rank;
5021   PetscInt       i, j;
5022   PetscErrorCode ierr;
5023 
5024   PetscFunctionBegin;
5025   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
5026   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
5027   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
5028   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
5029   numCIndices = numCIndices ? numCIndices : numRIndices;
5030   for (i = 0; i < numRIndices; i++) {
5031     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
5032     for (j = 0; j < numCIndices; j++) {
5033 #if defined(PETSC_USE_COMPLEX)
5034       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
5035 #else
5036       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
5037 #endif
5038     }
5039     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5040   }
5041   PetscFunctionReturn(0);
5042 }
5043 
5044 #undef __FUNCT__
5045 #define __FUNCT__ "indicesPoint_private"
5046 /* . off - The global offset of this point */
5047 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5048 {
5049   PetscInt        dof;    /* The number of unknowns on this point */
5050   PetscInt        cdof;   /* The number of constraints on this point */
5051   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5052   PetscInt        cind = 0, k;
5053   PetscErrorCode  ierr;
5054 
5055   PetscFunctionBegin;
5056   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5057   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5058   if (!cdof || setBC) {
5059     if (orientation >= 0) {
5060       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5061     } else {
5062       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5063     }
5064   } else {
5065     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5066     if (orientation >= 0) {
5067       for (k = 0; k < dof; ++k) {
5068         if ((cind < cdof) && (k == cdofs[cind])) {
5069           /* Insert check for returning constrained indices */
5070           indices[*loff+k] = -(off+k+1);
5071           ++cind;
5072         } else {
5073           indices[*loff+k] = off+k-cind;
5074         }
5075       }
5076     } else {
5077       for (k = 0; k < dof; ++k) {
5078         if ((cind < cdof) && (k == cdofs[cind])) {
5079           /* Insert check for returning constrained indices */
5080           indices[*loff+dof-k-1] = -(off+k+1);
5081           ++cind;
5082         } else {
5083           indices[*loff+dof-k-1] = off+k-cind;
5084         }
5085       }
5086     }
5087   }
5088   *loff += dof;
5089   PetscFunctionReturn(0);
5090 }
5091 
5092 #undef __FUNCT__
5093 #define __FUNCT__ "indicesPointFields_private"
5094 /* . off - The global offset of this point */
5095 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5096 {
5097   PetscInt       numFields, foff, f;
5098   PetscErrorCode ierr;
5099 
5100   PetscFunctionBegin;
5101   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5102   for (f = 0, foff = 0; f < numFields; ++f) {
5103     PetscInt        fdof, fcomp, cfdof;
5104     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5105     PetscInt        cind = 0, k, c;
5106 
5107     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5108     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5109     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5110     if (!cfdof || setBC) {
5111       if (orientation >= 0) {
5112         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5113       } else {
5114         for (k = fdof/fcomp-1; k >= 0; --k) {
5115           for (c = 0; c < fcomp; ++c) {
5116             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5117           }
5118         }
5119       }
5120     } else {
5121       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5122       if (orientation >= 0) {
5123         for (k = 0; k < fdof; ++k) {
5124           if ((cind < cfdof) && (k == fcdofs[cind])) {
5125             indices[foffs[f]+k] = -(off+foff+k+1);
5126             ++cind;
5127           } else {
5128             indices[foffs[f]+k] = off+foff+k-cind;
5129           }
5130         }
5131       } else {
5132         for (k = fdof/fcomp-1; k >= 0; --k) {
5133           for (c = 0; c < fcomp; ++c) {
5134             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5135               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5136               ++cind;
5137             } else {
5138               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5139             }
5140           }
5141         }
5142       }
5143     }
5144     foff     += fdof - cfdof;
5145     foffs[f] += fdof;
5146   }
5147   PetscFunctionReturn(0);
5148 }
5149 
5150 #undef __FUNCT__
5151 #define __FUNCT__ "DMPlexMatSetClosure"
5152 /*@C
5153   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5154 
5155   Not collective
5156 
5157   Input Parameters:
5158 + dm - The DM
5159 . section - The section describing the layout in v, or NULL to use the default section
5160 . globalSection - The section describing the layout in v, or NULL to use the default global section
5161 . A - The matrix
5162 . point - The sieve point in the DM
5163 . values - The array of values
5164 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5165 
5166   Fortran Notes:
5167   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5168 
5169   Level: intermediate
5170 
5171 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5172 @*/
5173 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5174 {
5175   DM_Plex        *mesh   = (DM_Plex*) dm->data;
5176   PetscSection    clSection;
5177   IS              clPoints;
5178   PetscInt       *points = NULL;
5179   const PetscInt *clp;
5180   PetscInt       *indices;
5181   PetscInt        offsets[32];
5182   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5183   PetscErrorCode  ierr;
5184 
5185   PetscFunctionBegin;
5186   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5187   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
5188   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5189   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
5190   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5191   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5192   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5193   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5194   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5195   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
5196   if (!clPoints) {
5197     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5198     /* Compress out points not in the section */
5199     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5200     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5201       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5202         points[q*2]   = points[p];
5203         points[q*2+1] = points[p+1];
5204         ++q;
5205       }
5206     }
5207     numPoints = q;
5208   } else {
5209     PetscInt dof, off;
5210 
5211     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
5212     numPoints = dof/2;
5213     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
5214     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
5215     points = (PetscInt *) &clp[off];
5216   }
5217   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5218     PetscInt fdof;
5219 
5220     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5221     for (f = 0; f < numFields; ++f) {
5222       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5223       offsets[f+1] += fdof;
5224     }
5225     numIndices += dof;
5226   }
5227   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5228 
5229   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5230   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5231   if (numFields) {
5232     for (p = 0; p < numPoints*2; p += 2) {
5233       PetscInt o = points[p+1];
5234       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5235       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5236     }
5237   } else {
5238     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5239       PetscInt o = points[p+1];
5240       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5241       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5242     }
5243   }
5244   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5245   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5246   if (ierr) {
5247     PetscMPIInt    rank;
5248     PetscErrorCode ierr2;
5249 
5250     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5251     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5252     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5253     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5254     CHKERRQ(ierr);
5255   }
5256   if (!clPoints) {
5257     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5258   } else {
5259     ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
5260   }
5261   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5262   PetscFunctionReturn(0);
5263 }
5264 
5265 #undef __FUNCT__
5266 #define __FUNCT__ "DMPlexMatSetClosureRefined"
5267 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5268 {
5269   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5270   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5271   PetscInt       *cpoints = NULL;
5272   PetscInt       *findices, *cindices;
5273   PetscInt        foffsets[32], coffsets[32];
5274   CellRefiner     cellRefiner;
5275   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5276   PetscErrorCode  ierr;
5277 
5278   PetscFunctionBegin;
5279   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5280   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5281   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5282   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5283   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5284   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5285   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5286   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5287   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5288   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5289   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5290   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5291   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5292   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5293   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5294   /* Column indices */
5295   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5296   maxFPoints = numCPoints;
5297   /* Compress out points not in the section */
5298   /*   TODO: Squeeze out points with 0 dof as well */
5299   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5300   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5301     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5302       cpoints[q*2]   = cpoints[p];
5303       cpoints[q*2+1] = cpoints[p+1];
5304       ++q;
5305     }
5306   }
5307   numCPoints = q;
5308   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5309     PetscInt fdof;
5310 
5311     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5312     if (!dof) continue;
5313     for (f = 0; f < numFields; ++f) {
5314       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5315       coffsets[f+1] += fdof;
5316     }
5317     numCIndices += dof;
5318   }
5319   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5320   /* Row indices */
5321   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5322   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5323   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5324   for (r = 0, q = 0; r < numSubcells; ++r) {
5325     /* TODO Map from coarse to fine cells */
5326     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5327     /* Compress out points not in the section */
5328     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5329     for (p = 0; p < numFPoints*2; p += 2) {
5330       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5331         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5332         if (!dof) continue;
5333         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5334         if (s < q) continue;
5335         ftotpoints[q*2]   = fpoints[p];
5336         ftotpoints[q*2+1] = fpoints[p+1];
5337         ++q;
5338       }
5339     }
5340     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5341   }
5342   numFPoints = q;
5343   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5344     PetscInt fdof;
5345 
5346     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5347     if (!dof) continue;
5348     for (f = 0; f < numFields; ++f) {
5349       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5350       foffsets[f+1] += fdof;
5351     }
5352     numFIndices += dof;
5353   }
5354   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5355 
5356   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5357   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5358   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5359   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5360   if (numFields) {
5361     for (p = 0; p < numFPoints*2; p += 2) {
5362       PetscInt o = ftotpoints[p+1];
5363       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5364       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5365     }
5366     for (p = 0; p < numCPoints*2; p += 2) {
5367       PetscInt o = cpoints[p+1];
5368       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5369       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5370     }
5371   } else {
5372     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5373       PetscInt o = ftotpoints[p+1];
5374       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5375       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5376     }
5377     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5378       PetscInt o = cpoints[p+1];
5379       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5380       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5381     }
5382   }
5383   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
5384   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5385   if (ierr) {
5386     PetscMPIInt    rank;
5387     PetscErrorCode ierr2;
5388 
5389     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5390     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5391     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5392     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5393     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5394     CHKERRQ(ierr);
5395   }
5396   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5397   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5398   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5399   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5400   PetscFunctionReturn(0);
5401 }
5402 
5403 #undef __FUNCT__
5404 #define __FUNCT__ "DMPlexGetHybridBounds"
5405 /*@
5406   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5407 
5408   Input Parameter:
5409 . dm - The DMPlex object
5410 
5411   Output Parameters:
5412 + cMax - The first hybrid cell
5413 . cMax - The first hybrid face
5414 . cMax - The first hybrid edge
5415 - cMax - The first hybrid vertex
5416 
5417   Level: developer
5418 
5419 .seealso DMPlexCreateHybridMesh()
5420 @*/
5421 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5422 {
5423   DM_Plex       *mesh = (DM_Plex*) dm->data;
5424   PetscInt       dim;
5425   PetscErrorCode ierr;
5426 
5427   PetscFunctionBegin;
5428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5429   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5430   if (cMax) *cMax = mesh->hybridPointMax[dim];
5431   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5432   if (eMax) *eMax = mesh->hybridPointMax[1];
5433   if (vMax) *vMax = mesh->hybridPointMax[0];
5434   PetscFunctionReturn(0);
5435 }
5436 
5437 #undef __FUNCT__
5438 #define __FUNCT__ "DMPlexSetHybridBounds"
5439 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5440 {
5441   DM_Plex       *mesh = (DM_Plex*) dm->data;
5442   PetscInt       dim;
5443   PetscErrorCode ierr;
5444 
5445   PetscFunctionBegin;
5446   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5447   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5448   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5449   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5450   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5451   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5452   PetscFunctionReturn(0);
5453 }
5454 
5455 #undef __FUNCT__
5456 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5457 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5458 {
5459   DM_Plex *mesh = (DM_Plex*) dm->data;
5460 
5461   PetscFunctionBegin;
5462   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5463   PetscValidPointer(cellHeight, 2);
5464   *cellHeight = mesh->vtkCellHeight;
5465   PetscFunctionReturn(0);
5466 }
5467 
5468 #undef __FUNCT__
5469 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5470 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5471 {
5472   DM_Plex *mesh = (DM_Plex*) dm->data;
5473 
5474   PetscFunctionBegin;
5475   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5476   mesh->vtkCellHeight = cellHeight;
5477   PetscFunctionReturn(0);
5478 }
5479 
5480 #undef __FUNCT__
5481 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5482 /* We can easily have a form that takes an IS instead */
5483 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5484 {
5485   PetscSection   section, globalSection;
5486   PetscInt      *numbers, p;
5487   PetscErrorCode ierr;
5488 
5489   PetscFunctionBegin;
5490   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5491   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5492   for (p = pStart; p < pEnd; ++p) {
5493     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5494   }
5495   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5496   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5497   ierr = PetscMalloc1((pEnd - pStart), &numbers);CHKERRQ(ierr);
5498   for (p = pStart; p < pEnd; ++p) {
5499     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5500     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5501     else                       numbers[p-pStart] += shift;
5502   }
5503   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5504   if (globalSize) {
5505     PetscLayout layout;
5506     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
5507     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
5508     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
5509   }
5510   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5511   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5512   PetscFunctionReturn(0);
5513 }
5514 
5515 #undef __FUNCT__
5516 #define __FUNCT__ "DMPlexGetCellNumbering"
5517 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5518 {
5519   DM_Plex       *mesh = (DM_Plex*) dm->data;
5520   PetscInt       cellHeight, cStart, cEnd, cMax;
5521   PetscErrorCode ierr;
5522 
5523   PetscFunctionBegin;
5524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5525   if (!mesh->globalCellNumbers) {
5526     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5527     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5528     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5529     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5530     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
5531   }
5532   *globalCellNumbers = mesh->globalCellNumbers;
5533   PetscFunctionReturn(0);
5534 }
5535 
5536 #undef __FUNCT__
5537 #define __FUNCT__ "DMPlexGetVertexNumbering"
5538 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5539 {
5540   DM_Plex       *mesh = (DM_Plex*) dm->data;
5541   PetscInt       vStart, vEnd, vMax;
5542   PetscErrorCode ierr;
5543 
5544   PetscFunctionBegin;
5545   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5546   if (!mesh->globalVertexNumbers) {
5547     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5548     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5549     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5550     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
5551   }
5552   *globalVertexNumbers = mesh->globalVertexNumbers;
5553   PetscFunctionReturn(0);
5554 }
5555 
5556 #undef __FUNCT__
5557 #define __FUNCT__ "DMPlexCreatePointNumbering"
5558 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5559 {
5560   IS             nums[4];
5561   PetscInt       depths[4];
5562   PetscInt       depth, d, shift = 0;
5563   PetscErrorCode ierr;
5564 
5565   PetscFunctionBegin;
5566   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5567   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5568   depths[0] = depth; depths[1] = 0;
5569   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5570   for (d = 0; d <= depth; ++d) {
5571     PetscInt pStart, pEnd, gsize;
5572 
5573     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
5574     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
5575     shift += gsize;
5576   }
5577   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5578   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
5579   PetscFunctionReturn(0);
5580 }
5581 
5582 
5583 #undef __FUNCT__
5584 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5585 /*@C
5586   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5587   the local section and an SF describing the section point overlap.
5588 
5589   Input Parameters:
5590   + s - The PetscSection for the local field layout
5591   . sf - The SF describing parallel layout of the section points
5592   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5593   . label - The label specifying the points
5594   - labelValue - The label stratum specifying the points
5595 
5596   Output Parameter:
5597   . gsection - The PetscSection for the global field layout
5598 
5599   Note: This gives negative sizes and offsets to points not owned by this process
5600 
5601   Level: developer
5602 
5603 .seealso: PetscSectionCreate()
5604 @*/
5605 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5606 {
5607   PetscInt      *neg = NULL, *tmpOff = NULL;
5608   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5609   PetscErrorCode ierr;
5610 
5611   PetscFunctionBegin;
5612   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
5613   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5614   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5615   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5616   if (nroots >= 0) {
5617     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5618     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
5619     if (nroots > pEnd-pStart) {
5620       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
5621     } else {
5622       tmpOff = &(*gsection)->atlasDof[-pStart];
5623     }
5624   }
5625   /* Mark ghost points with negative dof */
5626   for (p = pStart; p < pEnd; ++p) {
5627     PetscInt value;
5628 
5629     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5630     if (value != labelValue) continue;
5631     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5632     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5633     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5634     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5635     if (neg) neg[p] = -(dof+1);
5636   }
5637   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5638   if (nroots >= 0) {
5639     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5640     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5641     if (nroots > pEnd-pStart) {
5642       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5643     }
5644   }
5645   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5646   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5647     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5648     (*gsection)->atlasOff[p] = off;
5649     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5650   }
5651   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
5652   globalOff -= off;
5653   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5654     (*gsection)->atlasOff[p] += globalOff;
5655     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5656   }
5657   /* Put in negative offsets for ghost points */
5658   if (nroots >= 0) {
5659     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5660     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5661     if (nroots > pEnd-pStart) {
5662       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5663     }
5664   }
5665   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5666   ierr = PetscFree(neg);CHKERRQ(ierr);
5667   PetscFunctionReturn(0);
5668 }
5669 
5670 #undef __FUNCT__
5671 #define __FUNCT__ "DMPlexCheckSymmetry"
5672 /*@
5673   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5674 
5675   Input Parameters:
5676   + dm - The DMPlex object
5677 
5678   Note: This is a useful diagnostic when creating meshes programmatically.
5679 
5680   Level: developer
5681 
5682 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5683 @*/
5684 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5685 {
5686   PetscSection    coneSection, supportSection;
5687   const PetscInt *cone, *support;
5688   PetscInt        coneSize, c, supportSize, s;
5689   PetscInt        pStart, pEnd, p, csize, ssize;
5690   PetscErrorCode  ierr;
5691 
5692   PetscFunctionBegin;
5693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5694   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5695   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5696   /* Check that point p is found in the support of its cone points, and vice versa */
5697   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5698   for (p = pStart; p < pEnd; ++p) {
5699     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5700     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5701     for (c = 0; c < coneSize; ++c) {
5702       PetscBool dup = PETSC_FALSE;
5703       PetscInt  d;
5704       for (d = c-1; d >= 0; --d) {
5705         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5706       }
5707       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5708       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5709       for (s = 0; s < supportSize; ++s) {
5710         if (support[s] == p) break;
5711       }
5712       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5713         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
5714         for (s = 0; s < coneSize; ++s) {
5715           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
5716         }
5717         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5718         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
5719         for (s = 0; s < supportSize; ++s) {
5720           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
5721         }
5722         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5723         if (dup) {
5724           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5725         } else {
5726           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5727         }
5728       }
5729     }
5730     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5731     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5732     for (s = 0; s < supportSize; ++s) {
5733       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5734       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5735       for (c = 0; c < coneSize; ++c) {
5736         if (cone[c] == p) break;
5737       }
5738       if (c >= coneSize) {
5739         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
5740         for (c = 0; c < supportSize; ++c) {
5741           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
5742         }
5743         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5744         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
5745         for (c = 0; c < coneSize; ++c) {
5746           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
5747         }
5748         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5749         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5750       }
5751     }
5752   }
5753   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5754   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5755   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5756   PetscFunctionReturn(0);
5757 }
5758 
5759 #undef __FUNCT__
5760 #define __FUNCT__ "DMPlexCheckSkeleton"
5761 /*@
5762   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5763 
5764   Input Parameters:
5765 + dm - The DMPlex object
5766 . isSimplex - Are the cells simplices or tensor products
5767 - cellHeight - Normally 0
5768 
5769   Note: This is a useful diagnostic when creating meshes programmatically.
5770 
5771   Level: developer
5772 
5773 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5774 @*/
5775 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5776 {
5777   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5778   PetscErrorCode ierr;
5779 
5780   PetscFunctionBegin;
5781   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5782   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5783   switch (dim) {
5784   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5785   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5786   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5787   default:
5788     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5789   }
5790   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5791   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5792   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5793   cMax = cMax >= 0 ? cMax : cEnd;
5794   for (c = cStart; c < cMax; ++c) {
5795     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5796 
5797     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5798     for (cl = 0; cl < closureSize*2; cl += 2) {
5799       const PetscInt p = closure[cl];
5800       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5801     }
5802     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5803     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5804   }
5805   for (c = cMax; c < cEnd; ++c) {
5806     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5807 
5808     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5809     for (cl = 0; cl < closureSize*2; cl += 2) {
5810       const PetscInt p = closure[cl];
5811       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5812     }
5813     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5814     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5815   }
5816   PetscFunctionReturn(0);
5817 }
5818 
5819 #undef __FUNCT__
5820 #define __FUNCT__ "DMPlexCheckFaces"
5821 /*@
5822   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5823 
5824   Input Parameters:
5825 + dm - The DMPlex object
5826 . isSimplex - Are the cells simplices or tensor products
5827 - cellHeight - Normally 0
5828 
5829   Note: This is a useful diagnostic when creating meshes programmatically.
5830 
5831   Level: developer
5832 
5833 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5834 @*/
5835 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5836 {
5837   PetscInt       pMax[4];
5838   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5839   PetscErrorCode ierr;
5840 
5841   PetscFunctionBegin;
5842   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5843   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5844   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5845   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5846   for (h = cellHeight; h < dim; ++h) {
5847     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5848     for (c = cStart; c < cEnd; ++c) {
5849       const PetscInt *cone, *ornt, *faces;
5850       PetscInt        numFaces, faceSize, coneSize,f;
5851       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5852 
5853       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5854       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5855       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5856       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5857       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5858       for (cl = 0; cl < closureSize*2; cl += 2) {
5859         const PetscInt p = closure[cl];
5860         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5861       }
5862       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5863       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5864       for (f = 0; f < numFaces; ++f) {
5865         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5866 
5867         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5868         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5869           const PetscInt p = fclosure[cl];
5870           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5871         }
5872         if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d has %d vertices but should have %d", cone[f], f, c, fnumCorners, faceSize);
5873         for (v = 0; v < fnumCorners; ++v) {
5874           if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d vertex %d, %d != %d", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]);
5875         }
5876         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5877       }
5878       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5879       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5880     }
5881   }
5882   PetscFunctionReturn(0);
5883 }
5884 
5885 #undef __FUNCT__
5886 #define __FUNCT__ "DMCreateInterpolation_Plex"
5887 /* Pointwise interpolation
5888      Just code FEM for now
5889      u^f = I u^c
5890      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5891      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5892      I_{ij} = psi^f_i phi^c_j
5893 */
5894 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5895 {
5896   PetscSection   gsc, gsf;
5897   PetscInt       m, n;
5898   void          *ctx;
5899   PetscErrorCode ierr;
5900 
5901   PetscFunctionBegin;
5902   /*
5903   Loop over coarse cells
5904     Loop over coarse basis functions
5905       Loop over fine cells in coarse cell
5906         Loop over fine dual basis functions
5907           Evaluate coarse basis on fine dual basis quad points
5908           Sum
5909           Update local element matrix
5910     Accumulate to interpolation matrix
5911 
5912    Can extend PetscFEIntegrateJacobian_Basic() to do a specialized cell loop
5913   */
5914   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5915   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5916   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5917   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5918   /* We need to preallocate properly */
5919   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5920   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5921   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5922   ierr = MatSetUp(*interpolation);CHKERRQ(ierr);
5923   ierr = MatSetFromOptions(*interpolation);CHKERRQ(ierr);
5924   ierr = MatSetOption(*interpolation, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);CHKERRQ(ierr);
5925   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5926   ierr = DMPlexComputeInterpolatorFEM(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);
5927   /* Use naive scaling */
5928   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5929   PetscFunctionReturn(0);
5930 }
5931 
5932 #undef __FUNCT__
5933 #define __FUNCT__ "DMCreateInjection_Plex"
5934 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, VecScatter *ctx)
5935 {
5936   Vec             cv,  fv;
5937   IS              cis, fis, fpointIS;
5938   PetscSection    sc, gsc, gsf;
5939   const PetscInt *fpoints;
5940   PetscInt       *cindices, *findices;
5941   PetscInt        cpStart, cpEnd, m, off, cp;
5942   PetscErrorCode  ierr;
5943 
5944   PetscFunctionBegin;
5945   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5946   ierr = DMGetGlobalVector(dmFine, &fv);CHKERRQ(ierr);
5947   ierr = DMGetDefaultSection(dmCoarse, &sc);CHKERRQ(ierr);
5948   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5949   ierr = DMGetGlobalVector(dmCoarse, &cv);CHKERRQ(ierr);
5950   ierr = DMPlexCreateCoarsePointIS(dmCoarse, &fpointIS);CHKERRQ(ierr);
5951   ierr = PetscSectionGetConstrainedStorageSize(gsc, &m);CHKERRQ(ierr);
5952   ierr = PetscMalloc2(m,&cindices,m,&findices);CHKERRQ(ierr);
5953   ierr = PetscSectionGetChart(gsc, &cpStart, &cpEnd);CHKERRQ(ierr);
5954   ierr = ISGetIndices(fpointIS, &fpoints);CHKERRQ(ierr);
5955   for (cp = cpStart, off = 0; cp < cpEnd; ++cp) {
5956     const PetscInt *cdofsC = NULL;
5957     PetscInt        fp     = fpoints[cp-cpStart], dofC, cdofC, dofF, offC, offF, d, e;
5958 
5959     ierr = PetscSectionGetDof(gsc, cp, &dofC);CHKERRQ(ierr);
5960     if (dofC <= 0) continue;
5961     ierr = PetscSectionGetConstraintDof(sc, cp, &cdofC);CHKERRQ(ierr);
5962     ierr = PetscSectionGetDof(gsf, fp, &dofF);CHKERRQ(ierr);
5963     ierr = PetscSectionGetOffset(gsc, cp, &offC);CHKERRQ(ierr);
5964     ierr = PetscSectionGetOffset(gsf, fp, &offF);CHKERRQ(ierr);
5965     if (cdofC) {ierr = PetscSectionGetConstraintIndices(sc, cp, &cdofsC);CHKERRQ(ierr);}
5966     if (dofC != dofF) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d (%d) has %d coarse dofs != %d fine dofs", cp, fp, dofC, dofF);
5967     if (offC < 0 || offF < 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Coarse point %d has invalid offset %d (%d)", cp, offC, offF);
5968     for (d = 0, e = 0; d < dofC; ++d) {
5969       if (cdofsC && cdofsC[e] == d) {++e; continue;}
5970       cindices[off+d-e] = offC+d; findices[off+d-e] = offF+d;
5971     }
5972     if (e != cdofC) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d (%d) has invalid number of constraints %d != %d", cp, fp, e, cdofC);
5973     off += dofC-cdofC;
5974   }
5975   ierr = ISRestoreIndices(fpointIS, &fpoints);CHKERRQ(ierr);
5976   if (off != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of coarse dofs %d != %d", off, m);
5977   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
5978   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
5979   ierr = VecScatterCreate(cv, cis, fv, fis, ctx);CHKERRQ(ierr);
5980   ierr = ISDestroy(&cis);CHKERRQ(ierr);
5981   ierr = ISDestroy(&fis);CHKERRQ(ierr);
5982   ierr = DMRestoreGlobalVector(dmFine, &fv);CHKERRQ(ierr);
5983   ierr = DMRestoreGlobalVector(dmCoarse, &cv);CHKERRQ(ierr);
5984   ierr = ISDestroy(&fpointIS);CHKERRQ(ierr);
5985   PetscFunctionReturn(0);
5986 }
5987 
5988 #undef __FUNCT__
5989 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5990 /* Pointwise interpolation
5991      Just code FEM for now
5992      u^f = I u^c
5993      sum_k u^f_k phi^f_k = I sum_l u^c_l phi^c_l
5994      u^f_i = sum_l int psi^f_i I phi^c_l u^c_l
5995      I_{ij} = int psi^f_i phi^c_j
5996 */
5997 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5998 {
5999   PetscSection   section;
6000   IS            *bcPoints;
6001   PetscInt      *bcFields, *numComp, *numDof;
6002   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc, f;
6003   PetscErrorCode ierr;
6004 
6005   PetscFunctionBegin;
6006   /* Handle boundary conditions */
6007   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6008   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6009   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
6010   for (bd = 0; bd < numBd; ++bd) {
6011     PetscBool isEssential;
6012     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
6013     if (isEssential) ++numBC;
6014   }
6015   ierr = PetscMalloc2(numBC,&bcFields,numBC,&bcPoints);CHKERRQ(ierr);
6016   for (bd = 0, bc = 0; bd < numBd; ++bd) {
6017     const char     *bdLabel;
6018     DMLabel         label;
6019     const PetscInt *values;
6020     PetscInt        field, numValues;
6021     PetscBool       isEssential, has;
6022 
6023     ierr = DMPlexGetBoundary(dm, bd, &isEssential, &bdLabel, &field, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
6024     if (numValues != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Bug me and I will fix this");
6025     ierr = DMPlexHasLabel(dm, bdLabel, &has);CHKERRQ(ierr);
6026     if (!has) {
6027       ierr = DMPlexCreateLabel(dm, bdLabel);CHKERRQ(ierr);
6028       ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
6029       ierr = DMPlexMarkBoundaryFaces(dm, label);CHKERRQ(ierr);
6030     }
6031     ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
6032     /* Only want to do this for FEM */
6033     ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
6034     ierr = DMPlexLabelAddCells(dm, label);CHKERRQ(ierr);
6035     /* Filter out cells, if you actually want to constraint cells you need to do things by hand right now */
6036     if (isEssential) {
6037       IS              tmp;
6038       PetscInt       *newidx;
6039       const PetscInt *idx;
6040       PetscInt        cStart, cEnd, n, p, newn = 0;
6041 
6042       bcFields[bc] = field;
6043       ierr = DMPlexGetStratumIS(dm, bdLabel, values[0], &tmp);CHKERRQ(ierr);
6044       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6045       ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
6046       ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
6047       for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
6048       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
6049       newn = 0;
6050       for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
6051       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
6052       ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
6053       ierr = ISDestroy(&tmp);CHKERRQ(ierr);
6054     }
6055   }
6056   /* Handle discretization */
6057   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
6058   ierr = PetscMalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
6059   for (f = 0; f < numFields; ++f) {
6060     PetscFE         fe;
6061     const PetscInt *numFieldDof;
6062     PetscInt        d;
6063 
6064     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
6065     ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
6066     ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
6067     for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
6068   }
6069   for (f = 0; f < numFields; ++f) {
6070     PetscInt d;
6071     for (d = 1; d < dim; ++d) {
6072       if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
6073     }
6074   }
6075   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, NULL, &section);CHKERRQ(ierr);
6076   for (f = 0; f < numFields; ++f) {
6077     PetscFE     fe;
6078     const char *name;
6079 
6080     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
6081     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
6082     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
6083   }
6084   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
6085   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6086   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);}
6087   ierr = PetscFree2(bcFields,bcPoints);CHKERRQ(ierr);
6088   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
6089   PetscFunctionReturn(0);
6090 }
6091 
6092 #undef __FUNCT__
6093 #define __FUNCT__ "DMPlexGetCoarseDM"
6094 /*@
6095   DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
6096 
6097   Input Parameter:
6098 . dm - The DMPlex object
6099 
6100   Output Parameter:
6101 . cdm - The coarse DM
6102 
6103   Level: intermediate
6104 
6105 .seealso: DMPlexSetCoarseDM()
6106 @*/
6107 PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm)
6108 {
6109   PetscFunctionBegin;
6110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6111   PetscValidPointer(cdm, 2);
6112   *cdm = ((DM_Plex *) dm->data)->coarseMesh;
6113   PetscFunctionReturn(0);
6114 }
6115 
6116 #undef __FUNCT__
6117 #define __FUNCT__ "DMPlexSetCoarseDM"
6118 /*@
6119   DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
6120 
6121   Input Parameters:
6122 + dm - The DMPlex object
6123 - cdm - The coarse DM
6124 
6125   Level: intermediate
6126 
6127 .seealso: DMPlexGetCoarseDM()
6128 @*/
6129 PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm)
6130 {
6131   DM_Plex       *mesh;
6132   PetscErrorCode ierr;
6133 
6134   PetscFunctionBegin;
6135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6136   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
6137   mesh = (DM_Plex *) dm->data;
6138   ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr);
6139   mesh->coarseMesh = cdm;
6140   ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr);
6141   PetscFunctionReturn(0);
6142 }
6143