xref: /petsc/src/dm/impls/plex/plex.c (revision e08f174e7597416c756631fcfe0117854928b2ef)
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_Distribute, DMPLEX_Stratify;
8 
9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors  = 3;
180     PetscReal    scale      = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscInt    numLabels, l;
282     PetscMPIInt size;
283 
284     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
285     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
286     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
287     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
288     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
289     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
290     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
291     if (depth == 1) {
292       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
293       pEnd = pEnd - pStart;
294       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
295       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
296       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
297       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
298       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
299       pEnd = pEnd - pStart;
300       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
302       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
303       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
304     } else {
305       for (d = 0; d <= dim; d++) {
306         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
307         pEnd = pEnd - pStart;
308         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
309         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
310         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
311         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
312       }
313     }
314     ierr = PetscFree(sizes);CHKERRQ(ierr);
315     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
316     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
317     for (l = 0; l < numLabels; ++l) {
318       DMLabel         label;
319       const char     *name;
320       IS              valueIS;
321       const PetscInt *values;
322       PetscInt        numValues, v;
323 
324       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
325       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
326       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
327       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
328       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
329       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
330       for (v = 0; v < numValues; ++v) {
331         PetscInt size;
332 
333         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
334         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
335         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
336       }
337       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
338       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
339       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
340     }
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 #undef __FUNCT__
346 #define __FUNCT__ "DMView_Plex"
347 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
348 {
349   PetscBool      iascii, isbinary;
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
354   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
356   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
357   if (iascii) {
358     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
359 #if 0
360   } else if (isbinary) {
361     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
362 #endif
363   }
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMDestroy_Plex"
369 PetscErrorCode DMDestroy_Plex(DM dm)
370 {
371   DM_Plex       *mesh = (DM_Plex*) dm->data;
372   DMLabel        next  = mesh->labels;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (--mesh->refct > 0) PetscFunctionReturn(0);
377   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
379   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
380   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
382   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
383   while (next) {
384     DMLabel tmp = next->next;
385 
386     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
387     next = tmp;
388   }
389   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
391   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
392   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
393   ierr = PetscFree(mesh);CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "DMCreateMatrix_Plex"
399 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
400 {
401   PetscSection   section, sectionGlobal;
402   PetscInt       bs = -1;
403   PetscInt       localSize;
404   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
405   PetscErrorCode ierr;
406 
407   PetscFunctionBegin;
408 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
409   ierr = MatInitializePackage();CHKERRQ(ierr);
410 #endif
411   if (!mtype) mtype = MATAIJ;
412   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
413   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
414   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
415   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
416   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
417   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
418   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
419   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
420   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
421   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
422   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
423   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
424   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
425   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
426   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
427   /* Check for symmetric storage */
428   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
429   if (isSymmetric) {
430     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
431   }
432   if (!isShell) {
433     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
434     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
435 
436     if (bs < 0) {
437       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
438         PetscInt pStart, pEnd, p, dof, cdof;
439 
440         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
441         for (p = pStart; p < pEnd; ++p) {
442           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
443           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
444           if (dof-cdof) {
445             if (bs < 0) {
446               bs = dof-cdof;
447             } else if (bs != dof-cdof) {
448               /* Layout does not admit a pointwise block size */
449               bs = 1;
450               break;
451             }
452           }
453         }
454         /* Must have same blocksize on all procs (some might have no points) */
455         bsLocal = bs;
456         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
457         bsLocal = bs < 0 ? bsMax : bs;
458         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
459         if (bsMin != bsMax) {
460           bs = 1;
461         } else {
462           bs = bsMax;
463         }
464       } else {
465         bs = 1;
466       }
467     }
468     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
469     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
470     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
471     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
472     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
473     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
474     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 #undef __FUNCT__
480 #define __FUNCT__ "DMPlexGetDimension"
481 /*@
482   DMPlexGetDimension - Return the topological mesh dimension
483 
484   Not collective
485 
486   Input Parameter:
487 . mesh - The DMPlex
488 
489   Output Parameter:
490 . dim - The topological mesh dimension
491 
492   Level: beginner
493 
494 .seealso: DMPlexCreate()
495 @*/
496 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
497 {
498   DM_Plex *mesh = (DM_Plex*) dm->data;
499 
500   PetscFunctionBegin;
501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
502   PetscValidPointer(dim, 2);
503   *dim = mesh->dim;
504   PetscFunctionReturn(0);
505 }
506 
507 #undef __FUNCT__
508 #define __FUNCT__ "DMPlexSetDimension"
509 /*@
510   DMPlexSetDimension - Set the topological mesh dimension
511 
512   Collective on mesh
513 
514   Input Parameters:
515 + mesh - The DMPlex
516 - dim - The topological mesh dimension
517 
518   Level: beginner
519 
520 .seealso: DMPlexCreate()
521 @*/
522 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
523 {
524   DM_Plex *mesh = (DM_Plex*) dm->data;
525 
526   PetscFunctionBegin;
527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
528   PetscValidLogicalCollectiveInt(dm, dim, 2);
529   mesh->dim               = dim;
530   mesh->preallocCenterDim = dim;
531   PetscFunctionReturn(0);
532 }
533 
534 #undef __FUNCT__
535 #define __FUNCT__ "DMPlexGetChart"
536 /*@
537   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
538 
539   Not collective
540 
541   Input Parameter:
542 . mesh - The DMPlex
543 
544   Output Parameters:
545 + pStart - The first mesh point
546 - pEnd   - The upper bound for mesh points
547 
548   Level: beginner
549 
550 .seealso: DMPlexCreate(), DMPlexSetChart()
551 @*/
552 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
553 {
554   DM_Plex       *mesh = (DM_Plex*) dm->data;
555   PetscErrorCode ierr;
556 
557   PetscFunctionBegin;
558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
559   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
560   PetscFunctionReturn(0);
561 }
562 
563 #undef __FUNCT__
564 #define __FUNCT__ "DMPlexSetChart"
565 /*@
566   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
567 
568   Not collective
569 
570   Input Parameters:
571 + mesh - The DMPlex
572 . pStart - The first mesh point
573 - pEnd   - The upper bound for mesh points
574 
575   Output Parameters:
576 
577   Level: beginner
578 
579 .seealso: DMPlexCreate(), DMPlexGetChart()
580 @*/
581 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
582 {
583   DM_Plex       *mesh = (DM_Plex*) dm->data;
584   PetscErrorCode ierr;
585 
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
588   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
589   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 }
592 
593 #undef __FUNCT__
594 #define __FUNCT__ "DMPlexGetConeSize"
595 /*@
596   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
597 
598   Not collective
599 
600   Input Parameters:
601 + mesh - The DMPlex
602 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
603 
604   Output Parameter:
605 . size - The cone size for point p
606 
607   Level: beginner
608 
609 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
610 @*/
611 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
612 {
613   DM_Plex       *mesh = (DM_Plex*) dm->data;
614   PetscErrorCode ierr;
615 
616   PetscFunctionBegin;
617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
618   PetscValidPointer(size, 3);
619   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
620   PetscFunctionReturn(0);
621 }
622 
623 #undef __FUNCT__
624 #define __FUNCT__ "DMPlexSetConeSize"
625 /*@
626   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
627 
628   Not collective
629 
630   Input Parameters:
631 + mesh - The DMPlex
632 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
633 - size - The cone size for point p
634 
635   Output Parameter:
636 
637   Note:
638   This should be called after DMPlexSetChart().
639 
640   Level: beginner
641 
642 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
643 @*/
644 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
645 {
646   DM_Plex       *mesh = (DM_Plex*) dm->data;
647   PetscErrorCode ierr;
648 
649   PetscFunctionBegin;
650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
651   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
652 
653   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "DMPlexGetCone"
659 /*@C
660   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
661 
662   Not collective
663 
664   Input Parameters:
665 + mesh - The DMPlex
666 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
667 
668   Output Parameter:
669 . cone - An array of points which are on the in-edges for point p
670 
671   Level: beginner
672 
673   Fortran Notes:
674   Since it returns an array, this routine is only available in Fortran 90, and you must
675   include petsc.h90 in your code.
676 
677   You must also call DMPlexRestoreCone() after you finish using the returned array.
678 
679 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
680 @*/
681 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
682 {
683   DM_Plex       *mesh = (DM_Plex*) dm->data;
684   PetscInt       off;
685   PetscErrorCode ierr;
686 
687   PetscFunctionBegin;
688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
689   PetscValidPointer(cone, 3);
690   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
691   *cone = &mesh->cones[off];
692   PetscFunctionReturn(0);
693 }
694 
695 #undef __FUNCT__
696 #define __FUNCT__ "DMPlexSetCone"
697 /*@
698   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
699 
700   Not collective
701 
702   Input Parameters:
703 + mesh - The DMPlex
704 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
705 - cone - An array of points which are on the in-edges for point p
706 
707   Output Parameter:
708 
709   Note:
710   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
711 
712   Level: beginner
713 
714 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
715 @*/
716 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
717 {
718   DM_Plex       *mesh = (DM_Plex*) dm->data;
719   PetscInt       pStart, pEnd;
720   PetscInt       dof, off, c;
721   PetscErrorCode ierr;
722 
723   PetscFunctionBegin;
724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
725   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
726   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
727   if (dof) PetscValidPointer(cone, 3);
728   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
729   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);
730   for (c = 0; c < dof; ++c) {
731     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);
732     mesh->cones[off+c] = cone[c];
733   }
734   PetscFunctionReturn(0);
735 }
736 
737 #undef __FUNCT__
738 #define __FUNCT__ "DMPlexGetConeOrientation"
739 /*@C
740   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
741 
742   Not collective
743 
744   Input Parameters:
745 + mesh - The DMPlex
746 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
747 
748   Output Parameter:
749 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
750                     integer giving the prescription for cone traversal. If it is negative, the cone is
751                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
752                     the index of the cone point on which to start.
753 
754   Level: beginner
755 
756   Fortran Notes:
757   Since it returns an array, this routine is only available in Fortran 90, and you must
758   include petsc.h90 in your code.
759 
760   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
761 
762 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
763 @*/
764 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
765 {
766   DM_Plex       *mesh = (DM_Plex*) dm->data;
767   PetscInt       off;
768   PetscErrorCode ierr;
769 
770   PetscFunctionBegin;
771   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
772 #if defined(PETSC_USE_DEBUG)
773   {
774     PetscInt dof;
775     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
776     if (dof) PetscValidPointer(coneOrientation, 3);
777   }
778 #endif
779   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
780 
781   *coneOrientation = &mesh->coneOrientations[off];
782   PetscFunctionReturn(0);
783 }
784 
785 #undef __FUNCT__
786 #define __FUNCT__ "DMPlexSetConeOrientation"
787 /*@
788   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
789 
790   Not collective
791 
792   Input Parameters:
793 + mesh - The DMPlex
794 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
795 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
796                     integer giving the prescription for cone traversal. If it is negative, the cone is
797                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
798                     the index of the cone point on which to start.
799 
800   Output Parameter:
801 
802   Note:
803   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
804 
805   Level: beginner
806 
807 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
808 @*/
809 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
810 {
811   DM_Plex       *mesh = (DM_Plex*) dm->data;
812   PetscInt       pStart, pEnd;
813   PetscInt       dof, off, c;
814   PetscErrorCode ierr;
815 
816   PetscFunctionBegin;
817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
818   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
819   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
820   if (dof) PetscValidPointer(coneOrientation, 3);
821   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
822   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);
823   for (c = 0; c < dof; ++c) {
824     PetscInt cdof, o = coneOrientation[c];
825 
826     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
827     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);
828     mesh->coneOrientations[off+c] = o;
829   }
830   PetscFunctionReturn(0);
831 }
832 
833 #undef __FUNCT__
834 #define __FUNCT__ "DMPlexInsertCone"
835 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
836 {
837   DM_Plex       *mesh = (DM_Plex*) dm->data;
838   PetscInt       pStart, pEnd;
839   PetscInt       dof, off;
840   PetscErrorCode ierr;
841 
842   PetscFunctionBegin;
843   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
844   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
845   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);
846   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);
847   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
848   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
849   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);
850   mesh->cones[off+conePos] = conePoint;
851   PetscFunctionReturn(0);
852 }
853 
854 #undef __FUNCT__
855 #define __FUNCT__ "DMPlexInsertConeOrientation"
856 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
857 {
858   DM_Plex       *mesh = (DM_Plex*) dm->data;
859   PetscInt       pStart, pEnd;
860   PetscInt       dof, off;
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
865   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
866   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);
867   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
868   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
869   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);
870   mesh->coneOrientations[off+conePos] = coneOrientation;
871   PetscFunctionReturn(0);
872 }
873 
874 #undef __FUNCT__
875 #define __FUNCT__ "DMPlexGetSupportSize"
876 /*@
877   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
878 
879   Not collective
880 
881   Input Parameters:
882 + mesh - The DMPlex
883 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
884 
885   Output Parameter:
886 . size - The support size for point p
887 
888   Level: beginner
889 
890 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
891 @*/
892 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
893 {
894   DM_Plex       *mesh = (DM_Plex*) dm->data;
895   PetscErrorCode ierr;
896 
897   PetscFunctionBegin;
898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
899   PetscValidPointer(size, 3);
900   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
901   PetscFunctionReturn(0);
902 }
903 
904 #undef __FUNCT__
905 #define __FUNCT__ "DMPlexSetSupportSize"
906 /*@
907   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
908 
909   Not collective
910 
911   Input Parameters:
912 + mesh - The DMPlex
913 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
914 - size - The support size for point p
915 
916   Output Parameter:
917 
918   Note:
919   This should be called after DMPlexSetChart().
920 
921   Level: beginner
922 
923 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
924 @*/
925 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
926 {
927   DM_Plex       *mesh = (DM_Plex*) dm->data;
928   PetscErrorCode ierr;
929 
930   PetscFunctionBegin;
931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
932   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
933 
934   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
935   PetscFunctionReturn(0);
936 }
937 
938 #undef __FUNCT__
939 #define __FUNCT__ "DMPlexGetSupport"
940 /*@C
941   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
942 
943   Not collective
944 
945   Input Parameters:
946 + mesh - The DMPlex
947 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
948 
949   Output Parameter:
950 . support - An array of points which are on the out-edges for point p
951 
952   Level: beginner
953 
954   Fortran Notes:
955   Since it returns an array, this routine is only available in Fortran 90, and you must
956   include petsc.h90 in your code.
957 
958   You must also call DMPlexRestoreSupport() after you finish using the returned array.
959 
960 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
961 @*/
962 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
963 {
964   DM_Plex       *mesh = (DM_Plex*) dm->data;
965   PetscInt       off;
966   PetscErrorCode ierr;
967 
968   PetscFunctionBegin;
969   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
970   PetscValidPointer(support, 3);
971   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
972   *support = &mesh->supports[off];
973   PetscFunctionReturn(0);
974 }
975 
976 #undef __FUNCT__
977 #define __FUNCT__ "DMPlexSetSupport"
978 /*@
979   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
980 
981   Not collective
982 
983   Input Parameters:
984 + mesh - The DMPlex
985 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
986 - support - An array of points which are on the in-edges for point p
987 
988   Output Parameter:
989 
990   Note:
991   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
992 
993   Level: beginner
994 
995 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
996 @*/
997 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
998 {
999   DM_Plex       *mesh = (DM_Plex*) dm->data;
1000   PetscInt       pStart, pEnd;
1001   PetscInt       dof, off, c;
1002   PetscErrorCode ierr;
1003 
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1006   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1007   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1008   if (dof) PetscValidPointer(support, 3);
1009   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1010   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);
1011   for (c = 0; c < dof; ++c) {
1012     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);
1013     mesh->supports[off+c] = support[c];
1014   }
1015   PetscFunctionReturn(0);
1016 }
1017 
1018 #undef __FUNCT__
1019 #define __FUNCT__ "DMPlexInsertSupport"
1020 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1021 {
1022   DM_Plex       *mesh = (DM_Plex*) dm->data;
1023   PetscInt       pStart, pEnd;
1024   PetscInt       dof, off;
1025   PetscErrorCode ierr;
1026 
1027   PetscFunctionBegin;
1028   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1029   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1030   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1031   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1032   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);
1033   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);
1034   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);
1035   mesh->supports[off+supportPos] = supportPoint;
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1041 /*@C
1042   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1043 
1044   Not collective
1045 
1046   Input Parameters:
1047 + mesh - The DMPlex
1048 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1049 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1050 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1051 
1052   Output Parameters:
1053 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1054 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1055 
1056   Note:
1057   If using internal storage (points is NULL on input), each call overwrites the last output.
1058 
1059   Fortran Notes:
1060   Since it returns an array, this routine is only available in Fortran 90, and you must
1061   include petsc.h90 in your code.
1062 
1063   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1064 
1065   Level: beginner
1066 
1067 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1068 @*/
1069 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1070 {
1071   DM_Plex        *mesh = (DM_Plex*) dm->data;
1072   PetscInt       *closure, *fifo;
1073   const PetscInt *tmp = NULL, *tmpO = NULL;
1074   PetscInt        tmpSize, t;
1075   PetscInt        depth       = 0, maxSize;
1076   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1077   PetscErrorCode  ierr;
1078 
1079   PetscFunctionBegin;
1080   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1081   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1082   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1083   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1084   if (*points) {
1085     closure = *points;
1086   } else {
1087     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1088   }
1089   closure[0] = p; closure[1] = 0;
1090   /* This is only 1-level */
1091   if (useCone) {
1092     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1093     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1094     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1095   } else {
1096     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1097     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1098   }
1099   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1100     const PetscInt cp = tmp[t];
1101     const PetscInt co = tmpO ? tmpO[t] : 0;
1102 
1103     closure[closureSize]   = cp;
1104     closure[closureSize+1] = co;
1105     fifo[fifoSize]         = cp;
1106     fifo[fifoSize+1]       = co;
1107   }
1108   while (fifoSize - fifoStart) {
1109     const PetscInt q   = fifo[fifoStart];
1110     const PetscInt o   = fifo[fifoStart+1];
1111     const PetscInt rev = o >= 0 ? 0 : 1;
1112     const PetscInt off = rev ? -(o+1) : o;
1113 
1114     if (useCone) {
1115       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1116       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1117       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1118     } else {
1119       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1120       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1121       tmpO = NULL;
1122     }
1123     for (t = 0; t < tmpSize; ++t) {
1124       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1125       const PetscInt cp = tmp[i];
1126       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1127       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1128        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1129       PetscInt       co = tmpO ? tmpO[i] : 0;
1130       PetscInt       c;
1131 
1132       if (rev) {
1133         PetscInt childSize, coff;
1134         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1135         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1136         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1137       }
1138       /* Check for duplicate */
1139       for (c = 0; c < closureSize; c += 2) {
1140         if (closure[c] == cp) break;
1141       }
1142       if (c == closureSize) {
1143         closure[closureSize]   = cp;
1144         closure[closureSize+1] = co;
1145         fifo[fifoSize]         = cp;
1146         fifo[fifoSize+1]       = co;
1147         closureSize           += 2;
1148         fifoSize              += 2;
1149       }
1150     }
1151     fifoStart += 2;
1152   }
1153   if (numPoints) *numPoints = closureSize/2;
1154   if (points)    *points    = closure;
1155   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1156   PetscFunctionReturn(0);
1157 }
1158 
1159 #undef __FUNCT__
1160 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1161 /*@C
1162   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1163 
1164   Not collective
1165 
1166   Input Parameters:
1167 + mesh - The DMPlex
1168 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1169 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1170 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1171 
1172   Output Parameters:
1173 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1174 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1175 
1176   Note:
1177   If not using internal storage (points is not NULL on input), this call is unnecessary
1178 
1179   Fortran Notes:
1180   Since it returns an array, this routine is only available in Fortran 90, and you must
1181   include petsc.h90 in your code.
1182 
1183   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1184 
1185   Level: beginner
1186 
1187 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1188 @*/
1189 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1190 {
1191   PetscErrorCode ierr;
1192 
1193   PetscFunctionBegin;
1194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1195   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1196   PetscFunctionReturn(0);
1197 }
1198 
1199 #undef __FUNCT__
1200 #define __FUNCT__ "DMPlexGetMaxSizes"
1201 /*@
1202   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1203 
1204   Not collective
1205 
1206   Input Parameter:
1207 . mesh - The DMPlex
1208 
1209   Output Parameters:
1210 + maxConeSize - The maximum number of in-edges
1211 - maxSupportSize - The maximum number of out-edges
1212 
1213   Level: beginner
1214 
1215 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1216 @*/
1217 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1218 {
1219   DM_Plex *mesh = (DM_Plex*) dm->data;
1220 
1221   PetscFunctionBegin;
1222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1223   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1224   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 #undef __FUNCT__
1229 #define __FUNCT__ "DMSetUp_Plex"
1230 PetscErrorCode DMSetUp_Plex(DM dm)
1231 {
1232   DM_Plex       *mesh = (DM_Plex*) dm->data;
1233   PetscInt       size;
1234   PetscErrorCode ierr;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1238   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1239   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1240   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1241   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1242   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1243   if (mesh->maxSupportSize) {
1244     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1245     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1246     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1247   }
1248   PetscFunctionReturn(0);
1249 }
1250 
1251 #undef __FUNCT__
1252 #define __FUNCT__ "DMCreateSubDM_Plex"
1253 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1254 {
1255   PetscSection   section, sectionGlobal;
1256   PetscInt      *subIndices;
1257   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1258   PetscErrorCode ierr;
1259 
1260   PetscFunctionBegin;
1261   if (!numFields) PetscFunctionReturn(0);
1262   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1263   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1264   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1265   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1266   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1267   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1268   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1269   for (p = pStart; p < pEnd; ++p) {
1270     PetscInt gdof;
1271 
1272     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1273     if (gdof > 0) {
1274       for (f = 0; f < numFields; ++f) {
1275         PetscInt fdof, fcdof;
1276 
1277         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1278         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1279         subSize += fdof-fcdof;
1280       }
1281     }
1282   }
1283   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1284   for (p = pStart; p < pEnd; ++p) {
1285     PetscInt gdof, goff;
1286 
1287     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1288     if (gdof > 0) {
1289       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1290       for (f = 0; f < numFields; ++f) {
1291         PetscInt fdof, fcdof, fc, f2, poff = 0;
1292 
1293         /* Can get rid of this loop by storing field information in the global section */
1294         for (f2 = 0; f2 < fields[f]; ++f2) {
1295           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1296           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1297           poff += fdof-fcdof;
1298         }
1299         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1300         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1301         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1302           subIndices[subOff] = goff+poff+fc;
1303         }
1304       }
1305     }
1306   }
1307   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1308   if (subdm) {
1309     PetscSection subsection;
1310     PetscBool    haveNull = PETSC_FALSE;
1311     PetscInt     f, nf = 0;
1312 
1313     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1314     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1315     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1316     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1317     for (f = 0; f < numFields; ++f) {
1318       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1319       if ((*subdm)->nullspaceConstructors[f]) {
1320         haveNull = PETSC_TRUE;
1321         nf       = f;
1322       }
1323     }
1324     if (haveNull) {
1325       MatNullSpace nullSpace;
1326 
1327       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1328       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1329       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1330     }
1331     if (dm->fields) {
1332       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1333       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1334       for (f = 0; f < numFields; ++f) {
1335         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1336       }
1337       if (numFields == 1) {
1338         MatNullSpace space;
1339         Mat          pmat;
1340 
1341         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1342         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1343         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1344         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1345         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1346         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1347       }
1348     }
1349   }
1350   PetscFunctionReturn(0);
1351 }
1352 
1353 #undef __FUNCT__
1354 #define __FUNCT__ "DMPlexSymmetrize"
1355 /*@
1356   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1357 
1358   Not collective
1359 
1360   Input Parameter:
1361 . mesh - The DMPlex
1362 
1363   Output Parameter:
1364 
1365   Note:
1366   This should be called after all calls to DMPlexSetCone()
1367 
1368   Level: beginner
1369 
1370 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1371 @*/
1372 PetscErrorCode DMPlexSymmetrize(DM dm)
1373 {
1374   DM_Plex       *mesh = (DM_Plex*) dm->data;
1375   PetscInt      *offsets;
1376   PetscInt       supportSize;
1377   PetscInt       pStart, pEnd, p;
1378   PetscErrorCode ierr;
1379 
1380   PetscFunctionBegin;
1381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1382   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1383   /* Calculate support sizes */
1384   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1385   for (p = pStart; p < pEnd; ++p) {
1386     PetscInt dof, off, c;
1387 
1388     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1389     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1390     for (c = off; c < off+dof; ++c) {
1391       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1392     }
1393   }
1394   for (p = pStart; p < pEnd; ++p) {
1395     PetscInt dof;
1396 
1397     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1398 
1399     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1400   }
1401   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1402   /* Calculate supports */
1403   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1404   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1405   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1406   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1407   for (p = pStart; p < pEnd; ++p) {
1408     PetscInt dof, off, c;
1409 
1410     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1411     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1412     for (c = off; c < off+dof; ++c) {
1413       const PetscInt q = mesh->cones[c];
1414       PetscInt       offS;
1415 
1416       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1417 
1418       mesh->supports[offS+offsets[q]] = p;
1419       ++offsets[q];
1420     }
1421   }
1422   ierr = PetscFree(offsets);CHKERRQ(ierr);
1423   PetscFunctionReturn(0);
1424 }
1425 
1426 #undef __FUNCT__
1427 #define __FUNCT__ "DMPlexStratify"
1428 /*@
1429   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1430   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1431   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1432   the DAG.
1433 
1434   Not collective
1435 
1436   Input Parameter:
1437 . mesh - The DMPlex
1438 
1439   Output Parameter:
1440 
1441   Notes:
1442   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1443   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1444 
1445   This should be called after all calls to DMPlexSymmetrize()
1446 
1447   Level: beginner
1448 
1449 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1450 @*/
1451 PetscErrorCode DMPlexStratify(DM dm)
1452 {
1453   DMLabel        label;
1454   PetscInt       pStart, pEnd, p;
1455   PetscInt       numRoots = 0, numLeaves = 0;
1456   PetscErrorCode ierr;
1457 
1458   PetscFunctionBegin;
1459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1460   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1461   /* Calculate depth */
1462   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1463   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1464   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1465   /* Initialize roots and count leaves */
1466   for (p = pStart; p < pEnd; ++p) {
1467     PetscInt coneSize, supportSize;
1468 
1469     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1470     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1471     if (!coneSize && supportSize) {
1472       ++numRoots;
1473       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1474     } else if (!supportSize && coneSize) {
1475       ++numLeaves;
1476     } else if (!supportSize && !coneSize) {
1477       /* Isolated points */
1478       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1479     }
1480   }
1481   if (numRoots + numLeaves == (pEnd - pStart)) {
1482     for (p = pStart; p < pEnd; ++p) {
1483       PetscInt coneSize, supportSize;
1484 
1485       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1486       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1487       if (!supportSize && coneSize) {
1488         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1489       }
1490     }
1491   } else {
1492     IS       pointIS;
1493     PetscInt numPoints = 0, level = 0;
1494 
1495     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1496     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1497     while (numPoints) {
1498       const PetscInt *points;
1499       const PetscInt  newLevel = level+1;
1500 
1501       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1502       for (p = 0; p < numPoints; ++p) {
1503         const PetscInt  point = points[p];
1504         const PetscInt *support;
1505         PetscInt        supportSize, s;
1506 
1507         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1508         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1509         for (s = 0; s < supportSize; ++s) {
1510           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1511         }
1512       }
1513       ++level;
1514       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1515       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1516       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1517       else         {numPoints = 0;}
1518     }
1519     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1520   }
1521   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1522   PetscFunctionReturn(0);
1523 }
1524 
1525 #undef __FUNCT__
1526 #define __FUNCT__ "DMPlexGetJoin"
1527 /*@C
1528   DMPlexGetJoin - Get an array for the join of the set of points
1529 
1530   Not Collective
1531 
1532   Input Parameters:
1533 + dm - The DMPlex object
1534 . numPoints - The number of input points for the join
1535 - points - The input points
1536 
1537   Output Parameters:
1538 + numCoveredPoints - The number of points in the join
1539 - coveredPoints - The points in the join
1540 
1541   Level: intermediate
1542 
1543   Note: Currently, this is restricted to a single level join
1544 
1545   Fortran Notes:
1546   Since it returns an array, this routine is only available in Fortran 90, and you must
1547   include petsc.h90 in your code.
1548 
1549   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1550 
1551 .keywords: mesh
1552 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1553 @*/
1554 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1555 {
1556   DM_Plex       *mesh = (DM_Plex*) dm->data;
1557   PetscInt      *join[2];
1558   PetscInt       joinSize, i = 0;
1559   PetscInt       dof, off, p, c, m;
1560   PetscErrorCode ierr;
1561 
1562   PetscFunctionBegin;
1563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1564   PetscValidPointer(points, 2);
1565   PetscValidPointer(numCoveredPoints, 3);
1566   PetscValidPointer(coveredPoints, 4);
1567   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1568   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1569   /* Copy in support of first point */
1570   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1571   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1572   for (joinSize = 0; joinSize < dof; ++joinSize) {
1573     join[i][joinSize] = mesh->supports[off+joinSize];
1574   }
1575   /* Check each successive support */
1576   for (p = 1; p < numPoints; ++p) {
1577     PetscInt newJoinSize = 0;
1578 
1579     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1580     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1581     for (c = 0; c < dof; ++c) {
1582       const PetscInt point = mesh->supports[off+c];
1583 
1584       for (m = 0; m < joinSize; ++m) {
1585         if (point == join[i][m]) {
1586           join[1-i][newJoinSize++] = point;
1587           break;
1588         }
1589       }
1590     }
1591     joinSize = newJoinSize;
1592     i        = 1-i;
1593   }
1594   *numCoveredPoints = joinSize;
1595   *coveredPoints    = join[i];
1596   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1597   PetscFunctionReturn(0);
1598 }
1599 
1600 #undef __FUNCT__
1601 #define __FUNCT__ "DMPlexRestoreJoin"
1602 /*@C
1603   DMPlexRestoreJoin - Restore an array for the join of the set of points
1604 
1605   Not Collective
1606 
1607   Input Parameters:
1608 + dm - The DMPlex object
1609 . numPoints - The number of input points for the join
1610 - points - The input points
1611 
1612   Output Parameters:
1613 + numCoveredPoints - The number of points in the join
1614 - coveredPoints - The points in the join
1615 
1616   Fortran Notes:
1617   Since it returns an array, this routine is only available in Fortran 90, and you must
1618   include petsc.h90 in your code.
1619 
1620   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1621 
1622   Level: intermediate
1623 
1624 .keywords: mesh
1625 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1626 @*/
1627 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1628 {
1629   PetscErrorCode ierr;
1630 
1631   PetscFunctionBegin;
1632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1633   PetscValidPointer(coveredPoints, 4);
1634   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1635   PetscFunctionReturn(0);
1636 }
1637 
1638 #undef __FUNCT__
1639 #define __FUNCT__ "DMPlexGetFullJoin"
1640 /*@C
1641   DMPlexGetFullJoin - Get an array for the join of the set of points
1642 
1643   Not Collective
1644 
1645   Input Parameters:
1646 + dm - The DMPlex object
1647 . numPoints - The number of input points for the join
1648 - points - The input points
1649 
1650   Output Parameters:
1651 + numCoveredPoints - The number of points in the join
1652 - coveredPoints - The points in the join
1653 
1654   Fortran Notes:
1655   Since it returns an array, this routine is only available in Fortran 90, and you must
1656   include petsc.h90 in your code.
1657 
1658   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1659 
1660   Level: intermediate
1661 
1662 .keywords: mesh
1663 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1664 @*/
1665 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1666 {
1667   DM_Plex       *mesh = (DM_Plex*) dm->data;
1668   PetscInt      *offsets, **closures;
1669   PetscInt      *join[2];
1670   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1671   PetscInt       p, d, c, m;
1672   PetscErrorCode ierr;
1673 
1674   PetscFunctionBegin;
1675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1676   PetscValidPointer(points, 2);
1677   PetscValidPointer(numCoveredPoints, 3);
1678   PetscValidPointer(coveredPoints, 4);
1679 
1680   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1681   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1682   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1683   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1684   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1685   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1686   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1687 
1688   for (p = 0; p < numPoints; ++p) {
1689     PetscInt closureSize;
1690 
1691     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1692 
1693     offsets[p*(depth+2)+0] = 0;
1694     for (d = 0; d < depth+1; ++d) {
1695       PetscInt pStart, pEnd, i;
1696 
1697       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1698       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1699         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1700           offsets[p*(depth+2)+d+1] = i;
1701           break;
1702         }
1703       }
1704       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1705     }
1706     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);
1707   }
1708   for (d = 0; d < depth+1; ++d) {
1709     PetscInt dof;
1710 
1711     /* Copy in support of first point */
1712     dof = offsets[d+1] - offsets[d];
1713     for (joinSize = 0; joinSize < dof; ++joinSize) {
1714       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1715     }
1716     /* Check each successive cone */
1717     for (p = 1; p < numPoints && joinSize; ++p) {
1718       PetscInt newJoinSize = 0;
1719 
1720       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1721       for (c = 0; c < dof; ++c) {
1722         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1723 
1724         for (m = 0; m < joinSize; ++m) {
1725           if (point == join[i][m]) {
1726             join[1-i][newJoinSize++] = point;
1727             break;
1728           }
1729         }
1730       }
1731       joinSize = newJoinSize;
1732       i        = 1-i;
1733     }
1734     if (joinSize) break;
1735   }
1736   *numCoveredPoints = joinSize;
1737   *coveredPoints    = join[i];
1738   for (p = 0; p < numPoints; ++p) {
1739     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1740   }
1741   ierr = PetscFree(closures);CHKERRQ(ierr);
1742   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1743   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1744   PetscFunctionReturn(0);
1745 }
1746 
1747 #undef __FUNCT__
1748 #define __FUNCT__ "DMPlexGetMeet"
1749 /*@C
1750   DMPlexGetMeet - Get an array for the meet of the set of points
1751 
1752   Not Collective
1753 
1754   Input Parameters:
1755 + dm - The DMPlex object
1756 . numPoints - The number of input points for the meet
1757 - points - The input points
1758 
1759   Output Parameters:
1760 + numCoveredPoints - The number of points in the meet
1761 - coveredPoints - The points in the meet
1762 
1763   Level: intermediate
1764 
1765   Note: Currently, this is restricted to a single level meet
1766 
1767   Fortran Notes:
1768   Since it returns an array, this routine is only available in Fortran 90, and you must
1769   include petsc.h90 in your code.
1770 
1771   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1772 
1773 .keywords: mesh
1774 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1775 @*/
1776 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1777 {
1778   DM_Plex       *mesh = (DM_Plex*) dm->data;
1779   PetscInt      *meet[2];
1780   PetscInt       meetSize, i = 0;
1781   PetscInt       dof, off, p, c, m;
1782   PetscErrorCode ierr;
1783 
1784   PetscFunctionBegin;
1785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1786   PetscValidPointer(points, 2);
1787   PetscValidPointer(numCoveringPoints, 3);
1788   PetscValidPointer(coveringPoints, 4);
1789   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1790   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1791   /* Copy in cone of first point */
1792   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1793   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1794   for (meetSize = 0; meetSize < dof; ++meetSize) {
1795     meet[i][meetSize] = mesh->cones[off+meetSize];
1796   }
1797   /* Check each successive cone */
1798   for (p = 1; p < numPoints; ++p) {
1799     PetscInt newMeetSize = 0;
1800 
1801     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1802     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1803     for (c = 0; c < dof; ++c) {
1804       const PetscInt point = mesh->cones[off+c];
1805 
1806       for (m = 0; m < meetSize; ++m) {
1807         if (point == meet[i][m]) {
1808           meet[1-i][newMeetSize++] = point;
1809           break;
1810         }
1811       }
1812     }
1813     meetSize = newMeetSize;
1814     i        = 1-i;
1815   }
1816   *numCoveringPoints = meetSize;
1817   *coveringPoints    = meet[i];
1818   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1819   PetscFunctionReturn(0);
1820 }
1821 
1822 #undef __FUNCT__
1823 #define __FUNCT__ "DMPlexRestoreMeet"
1824 /*@C
1825   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1826 
1827   Not Collective
1828 
1829   Input Parameters:
1830 + dm - The DMPlex object
1831 . numPoints - The number of input points for the meet
1832 - points - The input points
1833 
1834   Output Parameters:
1835 + numCoveredPoints - The number of points in the meet
1836 - coveredPoints - The points in the meet
1837 
1838   Level: intermediate
1839 
1840   Fortran Notes:
1841   Since it returns an array, this routine is only available in Fortran 90, and you must
1842   include petsc.h90 in your code.
1843 
1844   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1845 
1846 .keywords: mesh
1847 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1848 @*/
1849 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1850 {
1851   PetscErrorCode ierr;
1852 
1853   PetscFunctionBegin;
1854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1855   PetscValidPointer(coveredPoints, 4);
1856   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1857   PetscFunctionReturn(0);
1858 }
1859 
1860 #undef __FUNCT__
1861 #define __FUNCT__ "DMPlexGetFullMeet"
1862 /*@C
1863   DMPlexGetFullMeet - Get an array for the meet of the set of points
1864 
1865   Not Collective
1866 
1867   Input Parameters:
1868 + dm - The DMPlex object
1869 . numPoints - The number of input points for the meet
1870 - points - The input points
1871 
1872   Output Parameters:
1873 + numCoveredPoints - The number of points in the meet
1874 - coveredPoints - The points in the meet
1875 
1876   Level: intermediate
1877 
1878   Fortran Notes:
1879   Since it returns an array, this routine is only available in Fortran 90, and you must
1880   include petsc.h90 in your code.
1881 
1882   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1883 
1884 .keywords: mesh
1885 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1886 @*/
1887 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1888 {
1889   DM_Plex       *mesh = (DM_Plex*) dm->data;
1890   PetscInt      *offsets, **closures;
1891   PetscInt      *meet[2];
1892   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1893   PetscInt       p, h, c, m;
1894   PetscErrorCode ierr;
1895 
1896   PetscFunctionBegin;
1897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1898   PetscValidPointer(points, 2);
1899   PetscValidPointer(numCoveredPoints, 3);
1900   PetscValidPointer(coveredPoints, 4);
1901 
1902   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1903   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1904   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1905   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1906   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1907   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1908 
1909   for (p = 0; p < numPoints; ++p) {
1910     PetscInt closureSize;
1911 
1912     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1913 
1914     offsets[p*(height+2)+0] = 0;
1915     for (h = 0; h < height+1; ++h) {
1916       PetscInt pStart, pEnd, i;
1917 
1918       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1919       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1920         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1921           offsets[p*(height+2)+h+1] = i;
1922           break;
1923         }
1924       }
1925       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1926     }
1927     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);
1928   }
1929   for (h = 0; h < height+1; ++h) {
1930     PetscInt dof;
1931 
1932     /* Copy in cone of first point */
1933     dof = offsets[h+1] - offsets[h];
1934     for (meetSize = 0; meetSize < dof; ++meetSize) {
1935       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1936     }
1937     /* Check each successive cone */
1938     for (p = 1; p < numPoints && meetSize; ++p) {
1939       PetscInt newMeetSize = 0;
1940 
1941       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1942       for (c = 0; c < dof; ++c) {
1943         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1944 
1945         for (m = 0; m < meetSize; ++m) {
1946           if (point == meet[i][m]) {
1947             meet[1-i][newMeetSize++] = point;
1948             break;
1949           }
1950         }
1951       }
1952       meetSize = newMeetSize;
1953       i        = 1-i;
1954     }
1955     if (meetSize) break;
1956   }
1957   *numCoveredPoints = meetSize;
1958   *coveredPoints    = meet[i];
1959   for (p = 0; p < numPoints; ++p) {
1960     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1961   }
1962   ierr = PetscFree(closures);CHKERRQ(ierr);
1963   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1964   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1965   PetscFunctionReturn(0);
1966 }
1967 
1968 #undef __FUNCT__
1969 #define __FUNCT__ "DMPlexGetNumFaceVertices"
1970 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1971 {
1972   MPI_Comm       comm;
1973   PetscErrorCode ierr;
1974 
1975   PetscFunctionBegin;
1976   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1977   PetscValidPointer(numFaceVertices,3);
1978   switch (cellDim) {
1979   case 0:
1980     *numFaceVertices = 0;
1981     break;
1982   case 1:
1983     *numFaceVertices = 1;
1984     break;
1985   case 2:
1986     switch (numCorners) {
1987     case 3: /* triangle */
1988       *numFaceVertices = 2; /* Edge has 2 vertices */
1989       break;
1990     case 4: /* quadrilateral */
1991       *numFaceVertices = 2; /* Edge has 2 vertices */
1992       break;
1993     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1994       *numFaceVertices = 3; /* Edge has 3 vertices */
1995       break;
1996     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1997       *numFaceVertices = 3; /* Edge has 3 vertices */
1998       break;
1999     default:
2000       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2001     }
2002     break;
2003   case 3:
2004     switch (numCorners) {
2005     case 4: /* tetradehdron */
2006       *numFaceVertices = 3; /* Face has 3 vertices */
2007       break;
2008     case 6: /* tet cohesive cells */
2009       *numFaceVertices = 4; /* Face has 4 vertices */
2010       break;
2011     case 8: /* hexahedron */
2012       *numFaceVertices = 4; /* Face has 4 vertices */
2013       break;
2014     case 9: /* tet cohesive Lagrange cells */
2015       *numFaceVertices = 6; /* Face has 6 vertices */
2016       break;
2017     case 10: /* quadratic tetrahedron */
2018       *numFaceVertices = 6; /* Face has 6 vertices */
2019       break;
2020     case 12: /* hex cohesive Lagrange cells */
2021       *numFaceVertices = 6; /* Face has 6 vertices */
2022       break;
2023     case 18: /* quadratic tet cohesive Lagrange cells */
2024       *numFaceVertices = 6; /* Face has 6 vertices */
2025       break;
2026     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2027       *numFaceVertices = 9; /* Face has 9 vertices */
2028       break;
2029     default:
2030       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2031     }
2032     break;
2033   default:
2034     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2035   }
2036   PetscFunctionReturn(0);
2037 }
2038 
2039 #undef __FUNCT__
2040 #define __FUNCT__ "DMPlexOrient"
2041 /* Trys to give the mesh a consistent orientation */
2042 PetscErrorCode DMPlexOrient(DM dm)
2043 {
2044   PetscBT        seenCells, flippedCells, seenFaces;
2045   PetscInt      *faceFIFO, fTop, fBottom;
2046   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
2047   PetscErrorCode ierr;
2048 
2049   PetscFunctionBegin;
2050   /* Truth Table
2051      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2052          F       0 flips     no         F             F           F
2053          F       1 flip      yes        F             T           T
2054          F       2 flips     no         T             F           T
2055          T       0 flips     yes        T             T           F
2056          T       1 flip      no
2057          T       2 flips     yes
2058   */
2059   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2060   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
2061   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
2062   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
2063   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
2064   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
2065   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
2066   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
2067   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
2068   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
2069   ierr = PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);CHKERRQ(ierr);
2070   fTop = fBottom = 0;
2071   /* Initialize FIFO with first cell */
2072   {
2073     const PetscInt *cone;
2074     PetscInt        coneSize;
2075 
2076     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
2077     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2078     for (c = 0; c < coneSize; ++c) {
2079       faceFIFO[fBottom++] = cone[c];
2080       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2081     }
2082   }
2083   /* Consider each face in FIFO */
2084   while (fTop < fBottom) {
2085     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2086     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2087     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2088 
2089     face = faceFIFO[fTop++];
2090     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2091     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2092     if (supportSize < 2) continue;
2093     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2094     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2095     flippedA = PetscBTLookup(flippedCells, support[0]-cStart);
2096     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2097     flippedB = PetscBTLookup(flippedCells, support[1]-cStart);
2098 
2099     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2100     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2101     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2102     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2103     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2104     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2105     for (c = 0; c < coneSizeA; ++c) {
2106       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2107         faceFIFO[fBottom++] = coneA[c];
2108         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2109       }
2110       if (coneA[c] == face) posA = c;
2111       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2112     }
2113     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2114     for (c = 0; c < coneSizeB; ++c) {
2115       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2116         faceFIFO[fBottom++] = coneB[c];
2117         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2118       }
2119       if (coneB[c] == face) posB = c;
2120       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2121     }
2122     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2123 
2124     if (dim == 1) {
2125       mismatch = posA == posB;
2126     } else {
2127       mismatch = coneOA[posA] == coneOB[posB];
2128     }
2129 
2130     if (mismatch ^ (flippedA ^ flippedB)) {
2131       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]);
2132       if (!seenA && !flippedA) {
2133         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2134       } else if (!seenB && !flippedB) {
2135         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2136       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2137     } else if (flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2138     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2139     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2140   }
2141 
2142   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2143   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2144   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2145   for (c = cStart; c < cEnd; ++c) {
2146     const PetscInt *cone, *coneO;
2147     PetscInt        coneSize, faceSize, cp;
2148 
2149     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2150     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2151     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2152     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2153     for (cp = 0; cp < coneSize; ++cp) {
2154       const PetscInt rcp = coneSize-cp-1;
2155 
2156       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2157       revcone[cp]  = cone[rcp];
2158       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2159     }
2160     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2161     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2162   }
2163   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2164   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2165   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2166   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2167   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2168   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2169   PetscFunctionReturn(0);
2170 }
2171 
2172 #undef __FUNCT__
2173 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2174 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2175 {
2176   const PetscInt *support = NULL;
2177   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2178   PetscErrorCode  ierr;
2179 
2180   PetscFunctionBegin;
2181   if (useClosure) {
2182     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2183     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2184     for (s = 0; s < supportSize; ++s) {
2185       const PetscInt *cone = NULL;
2186       PetscInt        coneSize, c, q;
2187 
2188       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2189       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2190       for (c = 0; c < coneSize; ++c) {
2191         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2192           if (cone[c] == adj[q]) break;
2193         }
2194         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2195       }
2196     }
2197   } else {
2198     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2199     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2200     for (s = 0; s < supportSize; ++s) {
2201       const PetscInt *cone = NULL;
2202       PetscInt        coneSize, c, q;
2203 
2204       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2205       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2206       for (c = 0; c < coneSize; ++c) {
2207         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2208           if (cone[c] == adj[q]) break;
2209         }
2210         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2211       }
2212     }
2213   }
2214   *adjSize = numAdj;
2215   PetscFunctionReturn(0);
2216 }
2217 
2218 #undef __FUNCT__
2219 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2220 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2221 {
2222   const PetscInt maxFaceCases = 30;
2223   PetscInt       numFaceCases = 0;
2224   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2225   PetscInt      *off, *adj;
2226   PetscInt      *neighborCells, *tmpClosure;
2227   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2228   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2229   PetscErrorCode ierr;
2230 
2231   PetscFunctionBegin;
2232   /* For parallel partitioning, I think you have to communicate supports */
2233   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2234   cellDim = dim - cellHeight;
2235   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2236   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2237   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2238   if (cEnd - cStart == 0) {
2239     if (numVertices) *numVertices = 0;
2240     if (offsets)   *offsets   = NULL;
2241     if (adjacency) *adjacency = NULL;
2242     PetscFunctionReturn(0);
2243   }
2244   numCells  = cEnd - cStart;
2245   faceDepth = depth - cellHeight;
2246   /* Setup face recognition */
2247   if (faceDepth == 1) {
2248     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2249 
2250     for (c = cStart; c < cEnd; ++c) {
2251       PetscInt corners;
2252 
2253       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2254       if (!cornersSeen[corners]) {
2255         PetscInt nFV;
2256 
2257         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2258         cornersSeen[corners] = 1;
2259 
2260         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2261 
2262         numFaceVertices[numFaceCases++] = nFV;
2263       }
2264     }
2265   }
2266   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2267   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2268   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2269   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2270   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2271   /* Count neighboring cells */
2272   for (cell = cStart; cell < cEnd; ++cell) {
2273     PetscInt numNeighbors = maxNeighbors, n;
2274 
2275     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2276     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2277     for (n = 0; n < numNeighbors; ++n) {
2278       PetscInt        cellPair[2];
2279       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2280       PetscInt        meetSize = 0;
2281       const PetscInt *meet    = NULL;
2282 
2283       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2284       if (cellPair[0] == cellPair[1]) continue;
2285       if (!found) {
2286         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2287         if (meetSize) {
2288           PetscInt f;
2289 
2290           for (f = 0; f < numFaceCases; ++f) {
2291             if (numFaceVertices[f] == meetSize) {
2292               found = PETSC_TRUE;
2293               break;
2294             }
2295           }
2296         }
2297         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2298       }
2299       if (found) ++off[cell-cStart+1];
2300     }
2301   }
2302   /* Prefix sum */
2303   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2304 
2305   if (adjacency) {
2306     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2307     /* Get neighboring cells */
2308     for (cell = cStart; cell < cEnd; ++cell) {
2309       PetscInt numNeighbors = maxNeighbors, n;
2310       PetscInt cellOffset   = 0;
2311 
2312       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2313       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2314       for (n = 0; n < numNeighbors; ++n) {
2315         PetscInt        cellPair[2];
2316         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2317         PetscInt        meetSize = 0;
2318         const PetscInt *meet    = NULL;
2319 
2320         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2321         if (cellPair[0] == cellPair[1]) continue;
2322         if (!found) {
2323           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2324           if (meetSize) {
2325             PetscInt f;
2326 
2327             for (f = 0; f < numFaceCases; ++f) {
2328               if (numFaceVertices[f] == meetSize) {
2329                 found = PETSC_TRUE;
2330                 break;
2331               }
2332             }
2333           }
2334           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2335         }
2336         if (found) {
2337           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2338           ++cellOffset;
2339         }
2340       }
2341     }
2342   }
2343   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2344   if (numVertices) *numVertices = numCells;
2345   if (offsets)   *offsets   = off;
2346   if (adjacency) *adjacency = adj;
2347   PetscFunctionReturn(0);
2348 }
2349 
2350 #if defined(PETSC_HAVE_CHACO)
2351 #if defined(PETSC_HAVE_UNISTD_H)
2352 #include <unistd.h>
2353 #endif
2354 /* Chaco does not have an include file */
2355 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2356                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2357                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2358                        int mesh_dims[3], double *goal, int global_method, int local_method,
2359                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2360 
2361 extern int FREE_GRAPH;
2362 
2363 #undef __FUNCT__
2364 #define __FUNCT__ "DMPlexPartition_Chaco"
2365 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2366 {
2367   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2368   MPI_Comm       comm;
2369   int            nvtxs          = numVertices; /* number of vertices in full graph */
2370   int           *vwgts          = NULL;   /* weights for all vertices */
2371   float         *ewgts          = NULL;   /* weights for all edges */
2372   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2373   char          *outassignname  = NULL;   /*  name of assignment output file */
2374   char          *outfilename    = NULL;   /* output file name */
2375   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2376   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2377   int            mesh_dims[3];            /* dimensions of mesh of processors */
2378   double        *goal          = NULL;    /* desired set sizes for each set */
2379   int            global_method = 1;       /* global partitioning algorithm */
2380   int            local_method  = 1;       /* local partitioning algorithm */
2381   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2382   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2383   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2384   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2385   long           seed          = 123636512; /* for random graph mutations */
2386   short int     *assignment;              /* Output partition */
2387   int            fd_stdout, fd_pipe[2];
2388   PetscInt      *points;
2389   PetscMPIInt    commSize;
2390   int            i, v, p;
2391   PetscErrorCode ierr;
2392 
2393   PetscFunctionBegin;
2394   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2395   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2396   if (!numVertices) {
2397     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2398     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2399     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2400     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2401     PetscFunctionReturn(0);
2402   }
2403   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2404   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2405 
2406   if (global_method == INERTIAL_METHOD) {
2407     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2408     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2409   }
2410   mesh_dims[0] = commSize;
2411   mesh_dims[1] = 1;
2412   mesh_dims[2] = 1;
2413   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2414   /* Chaco outputs to stdout. We redirect this to a buffer. */
2415   /* TODO: check error codes for UNIX calls */
2416 #if defined(PETSC_HAVE_UNISTD_H)
2417   {
2418     int piperet;
2419     piperet = pipe(fd_pipe);
2420     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2421     fd_stdout = dup(1);
2422     close(1);
2423     dup2(fd_pipe[1], 1);
2424   }
2425 #endif
2426   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2427                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2428                    vmax, ndims, eigtol, seed);
2429 #if defined(PETSC_HAVE_UNISTD_H)
2430   {
2431     char msgLog[10000];
2432     int  count;
2433 
2434     fflush(stdout);
2435     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2436     if (count < 0) count = 0;
2437     msgLog[count] = 0;
2438     close(1);
2439     dup2(fd_stdout, 1);
2440     close(fd_stdout);
2441     close(fd_pipe[0]);
2442     close(fd_pipe[1]);
2443     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2444   }
2445 #endif
2446   /* Convert to PetscSection+IS */
2447   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2448   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2449   for (v = 0; v < nvtxs; ++v) {
2450     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2451   }
2452   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2453   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2454   for (p = 0, i = 0; p < commSize; ++p) {
2455     for (v = 0; v < nvtxs; ++v) {
2456       if (assignment[v] == p) points[i++] = v;
2457     }
2458   }
2459   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2460   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2461   if (global_method == INERTIAL_METHOD) {
2462     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2463   }
2464   ierr = PetscFree(assignment);CHKERRQ(ierr);
2465   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2466   PetscFunctionReturn(0);
2467 }
2468 #endif
2469 
2470 #if defined(PETSC_HAVE_PARMETIS)
2471 #undef __FUNCT__
2472 #define __FUNCT__ "DMPlexPartition_ParMetis"
2473 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2474 {
2475   PetscFunctionBegin;
2476   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2477   PetscFunctionReturn(0);
2478 }
2479 #endif
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexEnlargePartition"
2483 /* Expand the partition by BFS on the adjacency graph */
2484 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2485 {
2486   PetscHashI      h;
2487   const PetscInt *points;
2488   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2489   PetscInt        pStart, pEnd, part, q;
2490   PetscErrorCode  ierr;
2491 
2492   PetscFunctionBegin;
2493   PetscHashICreate(h);
2494   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2495   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2496   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2497   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2498   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2499   for (part = pStart; part < pEnd; ++part) {
2500     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2501 
2502     PetscHashIClear(h);
2503     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2504     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2505     /* Add all existing points to h */
2506     for (p = 0; p < numPoints; ++p) {
2507       const PetscInt point = points[off+p];
2508       PetscHashIAdd(h, point, 1);
2509     }
2510     PetscHashISize(h, nP);
2511     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2512     /* Add all points in next BFS level */
2513     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2514     for (p = 0; p < numPoints; ++p) {
2515       const PetscInt point = points[off+p];
2516       PetscInt       s     = start[point], e = start[point+1], a;
2517 
2518       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2519     }
2520     PetscHashISize(h, numNewPoints);
2521     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2522     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2523     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2524     totPoints += numNewPoints;
2525   }
2526   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2527   PetscHashIDestroy(h);
2528   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2529   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2530   for (part = pStart, q = 0; part < pEnd; ++part) {
2531     PetscInt numPoints, p;
2532 
2533     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2534     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2535     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2536   }
2537   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2538   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2539   PetscFunctionReturn(0);
2540 }
2541 
2542 #undef __FUNCT__
2543 #define __FUNCT__ "DMPlexCreatePartition"
2544 /*
2545   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2546 
2547   Collective on DM
2548 
2549   Input Parameters:
2550   + dm - The DM
2551   . height - The height for points in the partition
2552   - enlarge - Expand each partition with neighbors
2553 
2554   Output Parameters:
2555   + partSection - The PetscSection giving the division of points by partition
2556   . partition - The list of points by partition
2557   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2558   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2559 
2560   Level: developer
2561 
2562 .seealso DMPlexDistribute()
2563 */
2564 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2565 {
2566   PetscMPIInt    size;
2567   PetscErrorCode ierr;
2568 
2569   PetscFunctionBegin;
2570   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2571 
2572   *origPartSection = NULL;
2573   *origPartition   = NULL;
2574   if (size == 1) {
2575     PetscInt *points;
2576     PetscInt  cStart, cEnd, c;
2577 
2578     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2579     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2580     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2581     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2582     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2583     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2584     for (c = cStart; c < cEnd; ++c) points[c] = c;
2585     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2586     PetscFunctionReturn(0);
2587   }
2588   if (height == 0) {
2589     PetscInt  numVertices;
2590     PetscInt *start     = NULL;
2591     PetscInt *adjacency = NULL;
2592 
2593     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2594     if (1) {
2595 #if defined(PETSC_HAVE_CHACO)
2596       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2597 #endif
2598     } else {
2599 #if defined(PETSC_HAVE_PARMETIS)
2600       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2601 #endif
2602     }
2603     if (enlarge) {
2604       *origPartSection = *partSection;
2605       *origPartition   = *partition;
2606 
2607       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2608     }
2609     ierr = PetscFree(start);CHKERRQ(ierr);
2610     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2611 # if 0
2612   } else if (height == 1) {
2613     /* Build the dual graph for faces and partition the hypergraph */
2614     PetscInt numEdges;
2615 
2616     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2617     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2618     destroyCSR(numEdges, start, adjacency);
2619 #endif
2620   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2621   PetscFunctionReturn(0);
2622 }
2623 
2624 #undef __FUNCT__
2625 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2626 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2627 {
2628   /* const PetscInt  height = 0; */
2629   const PetscInt *partArray;
2630   PetscInt       *allPoints, *packPoints;
2631   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2632   PetscErrorCode  ierr;
2633   PetscBT         bt;
2634   PetscSegBuffer  segpack,segpart;
2635 
2636   PetscFunctionBegin;
2637   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2638   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2639   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2640   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2641   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2642   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2643   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2644   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2645   for (rank = rStart; rank < rEnd; ++rank) {
2646     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2647 
2648     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2649     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2650     for (p = 0; p < numPoints; ++p) {
2651       PetscInt  point   = partArray[offset+p], closureSize, c;
2652       PetscInt *closure = NULL;
2653 
2654       /* TODO Include support for height > 0 case */
2655       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2656       for (c=0; c<closureSize; c++) {
2657         PetscInt cpoint = closure[c*2];
2658         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2659           PetscInt *PETSC_RESTRICT pt;
2660           partSize++;
2661           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2662           *pt = cpoint;
2663         }
2664       }
2665       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2666     }
2667     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2668     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2669     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2670     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2671     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2672   }
2673   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2674   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2675 
2676   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2677   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2678   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2679 
2680   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2681   for (rank = rStart; rank < rEnd; ++rank) {
2682     PetscInt numPoints, offset;
2683 
2684     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2685     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2686     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2687     packPoints += numPoints;
2688   }
2689 
2690   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2691   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2692   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2693   PetscFunctionReturn(0);
2694 }
2695 
2696 #undef __FUNCT__
2697 #define __FUNCT__ "DMPlexDistributeField"
2698 /*
2699   Input Parameters:
2700 . originalSection
2701 , originalVec
2702 
2703   Output Parameters:
2704 . newSection
2705 . newVec
2706 */
2707 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2708 {
2709   PetscSF        fieldSF;
2710   PetscInt      *remoteOffsets, fieldSize;
2711   PetscScalar   *originalValues, *newValues;
2712   PetscErrorCode ierr;
2713 
2714   PetscFunctionBegin;
2715   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2716 
2717   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2718   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2719   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2720 
2721   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2722   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2723   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2724   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2725   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2726   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2727   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2728   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2729   PetscFunctionReturn(0);
2730 }
2731 
2732 #undef __FUNCT__
2733 #define __FUNCT__ "DMPlexDistribute"
2734 /*@C
2735   DMPlexDistribute - Distributes the mesh and any associated sections.
2736 
2737   Not Collective
2738 
2739   Input Parameter:
2740 + dm  - The original DMPlex object
2741 . partitioner - The partitioning package, or NULL for the default
2742 - overlap - The overlap of partitions, 0 is the default
2743 
2744   Output Parameter:
2745 . parallelMesh - The distributed DMPlex object, or NULL
2746 
2747   Note: If the mesh was not distributed, the return value is NULL
2748 
2749   Level: intermediate
2750 
2751 .keywords: mesh, elements
2752 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2753 @*/
2754 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2755 {
2756   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2757   MPI_Comm               comm;
2758   const PetscInt         height = 0;
2759   PetscInt               dim, numRemoteRanks;
2760   IS                     origCellPart,        cellPart,        part;
2761   PetscSection           origCellPartSection, cellPartSection, partSection;
2762   PetscSFNode           *remoteRanks;
2763   PetscSF                partSF, pointSF, coneSF;
2764   ISLocalToGlobalMapping renumbering;
2765   PetscSection           originalConeSection, newConeSection;
2766   PetscInt              *remoteOffsets;
2767   PetscInt              *cones, *newCones, newConesSize;
2768   PetscBool              flg;
2769   PetscMPIInt            rank, numProcs, p;
2770   PetscErrorCode         ierr;
2771 
2772   PetscFunctionBegin;
2773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2774   PetscValidPointer(dmParallel,4);
2775 
2776   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2777   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2778   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2779   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2780 
2781   *dmParallel = NULL;
2782   if (numProcs == 1) PetscFunctionReturn(0);
2783 
2784   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2785   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2786   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2787   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2788   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2789   if (!rank) numRemoteRanks = numProcs;
2790   else       numRemoteRanks = 0;
2791   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2792   for (p = 0; p < numRemoteRanks; ++p) {
2793     remoteRanks[p].rank  = p;
2794     remoteRanks[p].index = 0;
2795   }
2796   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2797   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2798   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2799   if (flg) {
2800     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2801     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2802     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2803     if (origCellPart) {
2804       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2805       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2806       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2807     }
2808     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2809   }
2810   /* Close the partition over the mesh */
2811   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2812   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2813   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2814   /* Create new mesh */
2815   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2816   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2817   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2818   pmesh = (DM_Plex*) (*dmParallel)->data;
2819   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2820   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2821   if (flg) {
2822     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2823     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2824     ierr = ISView(part, NULL);CHKERRQ(ierr);
2825     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2826     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2827     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2828   }
2829   /* Distribute cone section */
2830   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2831   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2832   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2833   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2834   {
2835     PetscInt pStart, pEnd, p;
2836 
2837     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2838     for (p = pStart; p < pEnd; ++p) {
2839       PetscInt coneSize;
2840       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2841       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2842     }
2843   }
2844   /* Communicate and renumber cones */
2845   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2846   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2847   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2848   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2849   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2850   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2851   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2852   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2853   if (flg) {
2854     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2855     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2856     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2857     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2858     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2859   }
2860   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2861   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2862   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2863   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2864   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2865   /* Create supports and stratify sieve */
2866   {
2867     PetscInt pStart, pEnd;
2868 
2869     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2870     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2871   }
2872   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2873   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2874   /* Distribute Coordinates */
2875   {
2876     PetscSection originalCoordSection, newCoordSection;
2877     Vec          originalCoordinates, newCoordinates;
2878     const char  *name;
2879 
2880     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2881     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2882     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2883     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2884     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2885     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2886 
2887     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2888     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2889     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2890   }
2891   /* Distribute labels */
2892   {
2893     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2894     PetscInt numLabels = 0, l;
2895 
2896     /* Bcast number of labels */
2897     while (next) {
2898       ++numLabels; next = next->next;
2899     }
2900     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2901     next = mesh->labels;
2902     for (l = 0; l < numLabels; ++l) {
2903       DMLabel         newLabel;
2904       const PetscInt *partArray;
2905       char           *name;
2906       PetscInt       *stratumSizes = NULL, *points = NULL;
2907       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2908       PetscInt        nameSize, s, p;
2909       PetscBool       isdepth;
2910       size_t          len = 0;
2911 
2912       /* Bcast name (could filter for no points) */
2913       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2914       nameSize = len;
2915       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2916       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2917       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2918       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2919       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2920       if (isdepth) {            /* skip because "depth" is not distributed */
2921         ierr = PetscFree(name);CHKERRQ(ierr);
2922         if (!rank) next = next->next;
2923         continue;
2924       }
2925       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2926       newLabel->name = name;
2927       /* Bcast numStrata (could filter for no points in stratum) */
2928       if (!rank) newLabel->numStrata = next->numStrata;
2929       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2930       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2931                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2932                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2933       /* Bcast stratumValues (could filter for no points in stratum) */
2934       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2935       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2936       /* Find size on each process and Scatter */
2937       if (!rank) {
2938         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2939         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2940         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2941         for (s = 0; s < next->numStrata; ++s) {
2942           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2943             const PetscInt point = next->points[p];
2944             PetscInt       proc;
2945 
2946             for (proc = 0; proc < numProcs; ++proc) {
2947               PetscInt dof, off, pPart;
2948 
2949               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2950               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2951               for (pPart = off; pPart < off+dof; ++pPart) {
2952                 if (partArray[pPart] == point) {
2953                   ++stratumSizes[proc*next->numStrata+s];
2954                   break;
2955                 }
2956               }
2957             }
2958           }
2959         }
2960         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2961       }
2962       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2963       /* Calculate stratumOffsets */
2964       newLabel->stratumOffsets[0] = 0;
2965       for (s = 0; s < newLabel->numStrata; ++s) {
2966         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2967       }
2968       /* Pack points and Scatter */
2969       if (!rank) {
2970         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2971         displs[0] = 0;
2972         for (p = 0; p < numProcs; ++p) {
2973           sendcnts[p] = 0;
2974           for (s = 0; s < next->numStrata; ++s) {
2975             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2976           }
2977           offsets[p]  = displs[p];
2978           displs[p+1] = displs[p] + sendcnts[p];
2979         }
2980         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
2981         for (s = 0; s < next->numStrata; ++s) {
2982           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2983             const PetscInt point = next->points[p];
2984             PetscInt       proc;
2985 
2986             for (proc = 0; proc < numProcs; ++proc) {
2987               PetscInt dof, off, pPart;
2988 
2989               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2990               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2991               for (pPart = off; pPart < off+dof; ++pPart) {
2992                 if (partArray[pPart] == point) {
2993                   points[offsets[proc]++] = point;
2994                   break;
2995                 }
2996               }
2997             }
2998           }
2999         }
3000       }
3001       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3002       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3003       ierr = PetscFree(points);CHKERRQ(ierr);
3004       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3005       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3006       /* Renumber points */
3007       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3008       /* Sort points */
3009       for (s = 0; s < newLabel->numStrata; ++s) {
3010         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3011       }
3012       /* Insert into list */
3013       if (newNext) newNext->next = newLabel;
3014       else pmesh->labels = newLabel;
3015       newNext = newLabel;
3016       if (!rank) next = next->next;
3017     }
3018   }
3019   /* Cleanup Partition */
3020   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3021   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3022   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3023   ierr = ISDestroy(&part);CHKERRQ(ierr);
3024   /* Create point SF for parallel mesh */
3025   {
3026     const PetscInt *leaves;
3027     PetscSFNode    *remotePoints, *rowners, *lowners;
3028     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3029     PetscInt        pStart, pEnd;
3030 
3031     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3032     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3033     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3034     for (p=0; p<numRoots; p++) {
3035       rowners[p].rank  = -1;
3036       rowners[p].index = -1;
3037     }
3038     if (origCellPart) {
3039       /* Make sure cells in the original partition are not assigned to other procs */
3040       const PetscInt *origCells;
3041 
3042       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3043       for (p = 0; p < numProcs; ++p) {
3044         PetscInt dof, off, d;
3045 
3046         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3047         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3048         for (d = off; d < off+dof; ++d) {
3049           rowners[origCells[d]].rank = p;
3050         }
3051       }
3052       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3053     }
3054     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3055     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3056 
3057     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3058     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3059     for (p = 0; p < numLeaves; ++p) {
3060       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3061         lowners[p].rank  = rank;
3062         lowners[p].index = leaves ? leaves[p] : p;
3063       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3064         lowners[p].rank  = -2;
3065         lowners[p].index = -2;
3066       }
3067     }
3068     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3069       rowners[p].rank  = -3;
3070       rowners[p].index = -3;
3071     }
3072     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3073     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3074     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3075     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3076     for (p = 0; p < numLeaves; ++p) {
3077       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3078       if (lowners[p].rank != rank) ++numGhostPoints;
3079     }
3080     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3081     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3082     for (p = 0, gp = 0; p < numLeaves; ++p) {
3083       if (lowners[p].rank != rank) {
3084         ghostPoints[gp]        = leaves ? leaves[p] : p;
3085         remotePoints[gp].rank  = lowners[p].rank;
3086         remotePoints[gp].index = lowners[p].index;
3087         ++gp;
3088       }
3089     }
3090     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3091     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3092     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3093   }
3094   /* Cleanup */
3095   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3096   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3097   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3098   PetscFunctionReturn(0);
3099 }
3100 
3101 #undef __FUNCT__
3102 #define __FUNCT__ "DMPlexInvertCells_Internal"
3103 /* This is to fix the tetrahedron orientation from TetGen */
3104 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt numCells, PetscInt numCorners, int cells[])
3105 {
3106   PetscInt c;
3107 
3108   PetscFunctionBegin;
3109   if (numCorners != 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot invert cells with %d corners", numCorners);
3110   for (c = 0; c < numCells; ++c) {
3111     int *cone = &cells[c*4], tmpc;
3112 
3113     tmpc    = cone[0];
3114     cone[0] = cone[1];
3115     cone[1] = tmpc;
3116   }
3117   PetscFunctionReturn(0);
3118 }
3119 
3120 #if defined(PETSC_HAVE_TRIANGLE)
3121 #include <triangle.h>
3122 
3123 #undef __FUNCT__
3124 #define __FUNCT__ "InitInput_Triangle"
3125 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3126 {
3127   PetscFunctionBegin;
3128   inputCtx->numberofpoints             = 0;
3129   inputCtx->numberofpointattributes    = 0;
3130   inputCtx->pointlist                  = NULL;
3131   inputCtx->pointattributelist         = NULL;
3132   inputCtx->pointmarkerlist            = NULL;
3133   inputCtx->numberofsegments           = 0;
3134   inputCtx->segmentlist                = NULL;
3135   inputCtx->segmentmarkerlist          = NULL;
3136   inputCtx->numberoftriangleattributes = 0;
3137   inputCtx->trianglelist               = NULL;
3138   inputCtx->numberofholes              = 0;
3139   inputCtx->holelist                   = NULL;
3140   inputCtx->numberofregions            = 0;
3141   inputCtx->regionlist                 = NULL;
3142   PetscFunctionReturn(0);
3143 }
3144 
3145 #undef __FUNCT__
3146 #define __FUNCT__ "InitOutput_Triangle"
3147 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3148 {
3149   PetscFunctionBegin;
3150   outputCtx->numberofpoints        = 0;
3151   outputCtx->pointlist             = NULL;
3152   outputCtx->pointattributelist    = NULL;
3153   outputCtx->pointmarkerlist       = NULL;
3154   outputCtx->numberoftriangles     = 0;
3155   outputCtx->trianglelist          = NULL;
3156   outputCtx->triangleattributelist = NULL;
3157   outputCtx->neighborlist          = NULL;
3158   outputCtx->segmentlist           = NULL;
3159   outputCtx->segmentmarkerlist     = NULL;
3160   outputCtx->numberofedges         = 0;
3161   outputCtx->edgelist              = NULL;
3162   outputCtx->edgemarkerlist        = NULL;
3163   PetscFunctionReturn(0);
3164 }
3165 
3166 #undef __FUNCT__
3167 #define __FUNCT__ "FiniOutput_Triangle"
3168 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3169 {
3170   PetscFunctionBegin;
3171   free(outputCtx->pointmarkerlist);
3172   free(outputCtx->edgelist);
3173   free(outputCtx->edgemarkerlist);
3174   free(outputCtx->trianglelist);
3175   free(outputCtx->neighborlist);
3176   PetscFunctionReturn(0);
3177 }
3178 
3179 #undef __FUNCT__
3180 #define __FUNCT__ "DMPlexGenerate_Triangle"
3181 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3182 {
3183   MPI_Comm             comm;
3184   PetscInt             dim              = 2;
3185   const PetscBool      createConvexHull = PETSC_FALSE;
3186   const PetscBool      constrained      = PETSC_FALSE;
3187   struct triangulateio in;
3188   struct triangulateio out;
3189   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3190   PetscMPIInt          rank;
3191   PetscErrorCode       ierr;
3192 
3193   PetscFunctionBegin;
3194   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3195   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3196   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3197   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3198   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3199 
3200   in.numberofpoints = vEnd - vStart;
3201   if (in.numberofpoints > 0) {
3202     PetscSection coordSection;
3203     Vec          coordinates;
3204     PetscScalar *array;
3205 
3206     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3207     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3208     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3209     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3210     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3211     for (v = vStart; v < vEnd; ++v) {
3212       const PetscInt idx = v - vStart;
3213       PetscInt       off, d;
3214 
3215       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3216       for (d = 0; d < dim; ++d) {
3217         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3218       }
3219       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3220     }
3221     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3222   }
3223   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3224   in.numberofsegments = eEnd - eStart;
3225   if (in.numberofsegments > 0) {
3226     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3227     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3228     for (e = eStart; e < eEnd; ++e) {
3229       const PetscInt  idx = e - eStart;
3230       const PetscInt *cone;
3231 
3232       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3233 
3234       in.segmentlist[idx*2+0] = cone[0] - vStart;
3235       in.segmentlist[idx*2+1] = cone[1] - vStart;
3236 
3237       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3238     }
3239   }
3240 #if 0 /* Do not currently support holes */
3241   PetscReal *holeCoords;
3242   PetscInt   h, d;
3243 
3244   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3245   if (in.numberofholes > 0) {
3246     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3247     for (h = 0; h < in.numberofholes; ++h) {
3248       for (d = 0; d < dim; ++d) {
3249         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3250       }
3251     }
3252   }
3253 #endif
3254   if (!rank) {
3255     char args[32];
3256 
3257     /* Take away 'Q' for verbose output */
3258     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3259     if (createConvexHull) {
3260       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3261     }
3262     if (constrained) {
3263       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3264     }
3265     triangulate(args, &in, &out, NULL);
3266   }
3267   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3268   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3269   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3270   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3271   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3272 
3273   {
3274     const PetscInt numCorners  = 3;
3275     const PetscInt numCells    = out.numberoftriangles;
3276     const PetscInt numVertices = out.numberofpoints;
3277     const int     *cells      = out.trianglelist;
3278     const double  *meshCoords = out.pointlist;
3279 
3280     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3281     /* Set labels */
3282     for (v = 0; v < numVertices; ++v) {
3283       if (out.pointmarkerlist[v]) {
3284         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3285       }
3286     }
3287     if (interpolate) {
3288       for (e = 0; e < out.numberofedges; e++) {
3289         if (out.edgemarkerlist[e]) {
3290           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3291           const PetscInt *edges;
3292           PetscInt        numEdges;
3293 
3294           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3295           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3296           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3297           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3298         }
3299       }
3300     }
3301     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3302   }
3303 #if 0 /* Do not currently support holes */
3304   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3305 #endif
3306   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3307   PetscFunctionReturn(0);
3308 }
3309 
3310 #undef __FUNCT__
3311 #define __FUNCT__ "DMPlexRefine_Triangle"
3312 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3313 {
3314   MPI_Comm             comm;
3315   PetscInt             dim  = 2;
3316   struct triangulateio in;
3317   struct triangulateio out;
3318   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3319   PetscMPIInt          rank;
3320   PetscErrorCode       ierr;
3321 
3322   PetscFunctionBegin;
3323   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3324   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3325   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3326   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3327   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3328   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3329   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3330 
3331   in.numberofpoints = vEnd - vStart;
3332   if (in.numberofpoints > 0) {
3333     PetscSection coordSection;
3334     Vec          coordinates;
3335     PetscScalar *array;
3336 
3337     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3338     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3339     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3340     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3341     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3342     for (v = vStart; v < vEnd; ++v) {
3343       const PetscInt idx = v - vStart;
3344       PetscInt       off, d;
3345 
3346       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3347       for (d = 0; d < dim; ++d) {
3348         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3349       }
3350       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3351     }
3352     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3353   }
3354   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3355 
3356   in.numberofcorners   = 3;
3357   in.numberoftriangles = cEnd - cStart;
3358 
3359   in.trianglearealist  = (double*) maxVolumes;
3360   if (in.numberoftriangles > 0) {
3361     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3362     for (c = cStart; c < cEnd; ++c) {
3363       const PetscInt idx      = c - cStart;
3364       PetscInt      *closure = NULL;
3365       PetscInt       closureSize;
3366 
3367       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3368       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3369       for (v = 0; v < 3; ++v) {
3370         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3371       }
3372       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3373     }
3374   }
3375   /* TODO: Segment markers are missing on input */
3376 #if 0 /* Do not currently support holes */
3377   PetscReal *holeCoords;
3378   PetscInt   h, d;
3379 
3380   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3381   if (in.numberofholes > 0) {
3382     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3383     for (h = 0; h < in.numberofholes; ++h) {
3384       for (d = 0; d < dim; ++d) {
3385         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3386       }
3387     }
3388   }
3389 #endif
3390   if (!rank) {
3391     char args[32];
3392 
3393     /* Take away 'Q' for verbose output */
3394     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3395     triangulate(args, &in, &out, NULL);
3396   }
3397   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3398   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3399   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3400   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3401   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3402 
3403   {
3404     const PetscInt numCorners  = 3;
3405     const PetscInt numCells    = out.numberoftriangles;
3406     const PetscInt numVertices = out.numberofpoints;
3407     const int     *cells      = out.trianglelist;
3408     const double  *meshCoords = out.pointlist;
3409     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3410 
3411     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3412     /* Set labels */
3413     for (v = 0; v < numVertices; ++v) {
3414       if (out.pointmarkerlist[v]) {
3415         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3416       }
3417     }
3418     if (interpolate) {
3419       PetscInt e;
3420 
3421       for (e = 0; e < out.numberofedges; e++) {
3422         if (out.edgemarkerlist[e]) {
3423           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3424           const PetscInt *edges;
3425           PetscInt        numEdges;
3426 
3427           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3428           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3429           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3430           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3431         }
3432       }
3433     }
3434     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3435   }
3436 #if 0 /* Do not currently support holes */
3437   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3438 #endif
3439   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 #endif
3443 
3444 #if defined(PETSC_HAVE_TETGEN)
3445 #include <tetgen.h>
3446 #undef __FUNCT__
3447 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3448 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3449 {
3450   MPI_Comm       comm;
3451   const PetscInt dim  = 3;
3452   ::tetgenio     in;
3453   ::tetgenio     out;
3454   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3455   PetscMPIInt    rank;
3456   PetscErrorCode ierr;
3457 
3458   PetscFunctionBegin;
3459   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3460   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3461   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3462   in.numberofpoints = vEnd - vStart;
3463   if (in.numberofpoints > 0) {
3464     PetscSection coordSection;
3465     Vec          coordinates;
3466     PetscScalar *array;
3467 
3468     in.pointlist       = new double[in.numberofpoints*dim];
3469     in.pointmarkerlist = new int[in.numberofpoints];
3470 
3471     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3472     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3473     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3474     for (v = vStart; v < vEnd; ++v) {
3475       const PetscInt idx = v - vStart;
3476       PetscInt       off, d;
3477 
3478       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3479       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3480       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3481     }
3482     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3483   }
3484   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3485 
3486   in.numberoffacets = fEnd - fStart;
3487   if (in.numberoffacets > 0) {
3488     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3489     in.facetmarkerlist = new int[in.numberoffacets];
3490     for (f = fStart; f < fEnd; ++f) {
3491       const PetscInt idx     = f - fStart;
3492       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3493 
3494       in.facetlist[idx].numberofpolygons = 1;
3495       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3496       in.facetlist[idx].numberofholes    = 0;
3497       in.facetlist[idx].holelist         = NULL;
3498 
3499       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3500       for (p = 0; p < numPoints*2; p += 2) {
3501         const PetscInt point = points[p];
3502         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3503       }
3504 
3505       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3506       poly->numberofvertices = numVertices;
3507       poly->vertexlist       = new int[poly->numberofvertices];
3508       for (v = 0; v < numVertices; ++v) {
3509         const PetscInt vIdx = points[v] - vStart;
3510         poly->vertexlist[v] = vIdx;
3511       }
3512       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3513       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3514     }
3515   }
3516   if (!rank) {
3517     char args[32];
3518 
3519     /* Take away 'Q' for verbose output */
3520     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3521     ::tetrahedralize(args, &in, &out);
3522   }
3523   {
3524     const PetscInt numCorners  = 4;
3525     const PetscInt numCells    = out.numberoftetrahedra;
3526     const PetscInt numVertices = out.numberofpoints;
3527     const double   *meshCoords = out.pointlist;
3528     int            *cells      = out.tetrahedronlist;
3529 
3530     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3531     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3532     /* Set labels */
3533     for (v = 0; v < numVertices; ++v) {
3534       if (out.pointmarkerlist[v]) {
3535         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3536       }
3537     }
3538     if (interpolate) {
3539       PetscInt e;
3540 
3541       for (e = 0; e < out.numberofedges; e++) {
3542         if (out.edgemarkerlist[e]) {
3543           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3544           const PetscInt *edges;
3545           PetscInt        numEdges;
3546 
3547           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3548           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3549           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3550           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3551         }
3552       }
3553       for (f = 0; f < out.numberoftrifaces; f++) {
3554         if (out.trifacemarkerlist[f]) {
3555           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3556           const PetscInt *faces;
3557           PetscInt        numFaces;
3558 
3559           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3560           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3561           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3562           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3563         }
3564       }
3565     }
3566     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3567   }
3568   PetscFunctionReturn(0);
3569 }
3570 
3571 #undef __FUNCT__
3572 #define __FUNCT__ "DMPlexRefine_Tetgen"
3573 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3574 {
3575   MPI_Comm       comm;
3576   const PetscInt dim  = 3;
3577   ::tetgenio     in;
3578   ::tetgenio     out;
3579   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3580   PetscMPIInt    rank;
3581   PetscErrorCode ierr;
3582 
3583   PetscFunctionBegin;
3584   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3585   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3586   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3587   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3588   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3589 
3590   in.numberofpoints = vEnd - vStart;
3591   if (in.numberofpoints > 0) {
3592     PetscSection coordSection;
3593     Vec          coordinates;
3594     PetscScalar *array;
3595 
3596     in.pointlist       = new double[in.numberofpoints*dim];
3597     in.pointmarkerlist = new int[in.numberofpoints];
3598 
3599     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3600     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3601     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3602     for (v = vStart; v < vEnd; ++v) {
3603       const PetscInt idx = v - vStart;
3604       PetscInt       off, d;
3605 
3606       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3607       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3608       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3609     }
3610     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3611   }
3612   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3613 
3614   in.numberofcorners       = 4;
3615   in.numberoftetrahedra    = cEnd - cStart;
3616   in.tetrahedronvolumelist = (double*) maxVolumes;
3617   if (in.numberoftetrahedra > 0) {
3618     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3619     for (c = cStart; c < cEnd; ++c) {
3620       const PetscInt idx      = c - cStart;
3621       PetscInt      *closure = NULL;
3622       PetscInt       closureSize;
3623 
3624       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3625       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3626       for (v = 0; v < 4; ++v) {
3627         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3628       }
3629       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3630     }
3631   }
3632   /* TODO: Put in boundary faces with markers */
3633   if (!rank) {
3634     char args[32];
3635 
3636     /* Take away 'Q' for verbose output */
3637     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3638     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3639     ::tetrahedralize(args, &in, &out);
3640   }
3641   in.tetrahedronvolumelist = NULL;
3642 
3643   {
3644     const PetscInt numCorners  = 4;
3645     const PetscInt numCells    = out.numberoftetrahedra;
3646     const PetscInt numVertices = out.numberofpoints;
3647     const double   *meshCoords = out.pointlist;
3648     int            *cells      = out.tetrahedronlist;
3649 
3650     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3651 
3652     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3653     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3654     /* Set labels */
3655     for (v = 0; v < numVertices; ++v) {
3656       if (out.pointmarkerlist[v]) {
3657         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3658       }
3659     }
3660     if (interpolate) {
3661       PetscInt e, f;
3662 
3663       for (e = 0; e < out.numberofedges; e++) {
3664         if (out.edgemarkerlist[e]) {
3665           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3666           const PetscInt *edges;
3667           PetscInt        numEdges;
3668 
3669           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3670           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3671           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3672           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3673         }
3674       }
3675       for (f = 0; f < out.numberoftrifaces; f++) {
3676         if (out.trifacemarkerlist[f]) {
3677           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3678           const PetscInt *faces;
3679           PetscInt        numFaces;
3680 
3681           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3682           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3683           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3684           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3685         }
3686       }
3687     }
3688     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3689   }
3690   PetscFunctionReturn(0);
3691 }
3692 #endif
3693 
3694 #if defined(PETSC_HAVE_CTETGEN)
3695 #include "ctetgen.h"
3696 
3697 #undef __FUNCT__
3698 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3699 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3700 {
3701   MPI_Comm       comm;
3702   const PetscInt dim  = 3;
3703   PLC           *in, *out;
3704   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3705   PetscMPIInt    rank;
3706   PetscErrorCode ierr;
3707 
3708   PetscFunctionBegin;
3709   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3710   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3711   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3712   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3713   ierr = PLCCreate(&in);CHKERRQ(ierr);
3714   ierr = PLCCreate(&out);CHKERRQ(ierr);
3715 
3716   in->numberofpoints = vEnd - vStart;
3717   if (in->numberofpoints > 0) {
3718     PetscSection coordSection;
3719     Vec          coordinates;
3720     PetscScalar *array;
3721 
3722     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3723     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3724     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3725     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3726     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3727     for (v = vStart; v < vEnd; ++v) {
3728       const PetscInt idx = v - vStart;
3729       PetscInt       off, d, m;
3730 
3731       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3732       for (d = 0; d < dim; ++d) {
3733         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3734       }
3735       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3736 
3737       in->pointmarkerlist[idx] = (int) m;
3738     }
3739     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3740   }
3741   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3742 
3743   in->numberoffacets = fEnd - fStart;
3744   if (in->numberoffacets > 0) {
3745     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3746     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3747     for (f = fStart; f < fEnd; ++f) {
3748       const PetscInt idx     = f - fStart;
3749       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3750       polygon       *poly;
3751 
3752       in->facetlist[idx].numberofpolygons = 1;
3753 
3754       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3755 
3756       in->facetlist[idx].numberofholes    = 0;
3757       in->facetlist[idx].holelist         = NULL;
3758 
3759       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3760       for (p = 0; p < numPoints*2; p += 2) {
3761         const PetscInt point = points[p];
3762         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3763       }
3764 
3765       poly                   = in->facetlist[idx].polygonlist;
3766       poly->numberofvertices = numVertices;
3767       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3768       for (v = 0; v < numVertices; ++v) {
3769         const PetscInt vIdx = points[v] - vStart;
3770         poly->vertexlist[v] = vIdx;
3771       }
3772       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3773       in->facetmarkerlist[idx] = (int) m;
3774       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3775     }
3776   }
3777   if (!rank) {
3778     TetGenOpts t;
3779 
3780     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3781     t.in        = boundary; /* Should go away */
3782     t.plc       = 1;
3783     t.quality   = 1;
3784     t.edgesout  = 1;
3785     t.zeroindex = 1;
3786     t.quiet     = 1;
3787     t.verbose   = verbose;
3788     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3789     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3790   }
3791   {
3792     const PetscInt numCorners  = 4;
3793     const PetscInt numCells    = out->numberoftetrahedra;
3794     const PetscInt numVertices = out->numberofpoints;
3795     const double   *meshCoords = out->pointlist;
3796     int            *cells      = out->tetrahedronlist;
3797 
3798     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3799     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3800     /* Set labels */
3801     for (v = 0; v < numVertices; ++v) {
3802       if (out->pointmarkerlist[v]) {
3803         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3804       }
3805     }
3806     if (interpolate) {
3807       PetscInt e;
3808 
3809       for (e = 0; e < out->numberofedges; e++) {
3810         if (out->edgemarkerlist[e]) {
3811           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3812           const PetscInt *edges;
3813           PetscInt        numEdges;
3814 
3815           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3816           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3817           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3818           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3819         }
3820       }
3821       for (f = 0; f < out->numberoftrifaces; f++) {
3822         if (out->trifacemarkerlist[f]) {
3823           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3824           const PetscInt *faces;
3825           PetscInt        numFaces;
3826 
3827           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3828           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3829           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3830           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3831         }
3832       }
3833     }
3834     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3835   }
3836 
3837   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3838   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3839   PetscFunctionReturn(0);
3840 }
3841 
3842 #undef __FUNCT__
3843 #define __FUNCT__ "DMPlexRefine_CTetgen"
3844 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3845 {
3846   MPI_Comm       comm;
3847   const PetscInt dim  = 3;
3848   PLC           *in, *out;
3849   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3850   PetscMPIInt    rank;
3851   PetscErrorCode ierr;
3852 
3853   PetscFunctionBegin;
3854   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3855   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3856   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3857   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3858   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3859   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3860   ierr = PLCCreate(&in);CHKERRQ(ierr);
3861   ierr = PLCCreate(&out);CHKERRQ(ierr);
3862 
3863   in->numberofpoints = vEnd - vStart;
3864   if (in->numberofpoints > 0) {
3865     PetscSection coordSection;
3866     Vec          coordinates;
3867     PetscScalar *array;
3868 
3869     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3870     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3871     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3872     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3873     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3874     for (v = vStart; v < vEnd; ++v) {
3875       const PetscInt idx = v - vStart;
3876       PetscInt       off, d, m;
3877 
3878       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3879       for (d = 0; d < dim; ++d) {
3880         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3881       }
3882       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3883 
3884       in->pointmarkerlist[idx] = (int) m;
3885     }
3886     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3887   }
3888   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3889 
3890   in->numberofcorners       = 4;
3891   in->numberoftetrahedra    = cEnd - cStart;
3892   in->tetrahedronvolumelist = maxVolumes;
3893   if (in->numberoftetrahedra > 0) {
3894     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3895     for (c = cStart; c < cEnd; ++c) {
3896       const PetscInt idx      = c - cStart;
3897       PetscInt      *closure = NULL;
3898       PetscInt       closureSize;
3899 
3900       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3901       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3902       for (v = 0; v < 4; ++v) {
3903         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3904       }
3905       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3906     }
3907   }
3908   if (!rank) {
3909     TetGenOpts t;
3910 
3911     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3912 
3913     t.in        = dm; /* Should go away */
3914     t.refine    = 1;
3915     t.varvolume = 1;
3916     t.quality   = 1;
3917     t.edgesout  = 1;
3918     t.zeroindex = 1;
3919     t.quiet     = 1;
3920     t.verbose   = verbose; /* Change this */
3921 
3922     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3923     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3924   }
3925   {
3926     const PetscInt numCorners  = 4;
3927     const PetscInt numCells    = out->numberoftetrahedra;
3928     const PetscInt numVertices = out->numberofpoints;
3929     const double   *meshCoords = out->pointlist;
3930     int            *cells      = out->tetrahedronlist;
3931     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3932 
3933     ierr = DMPlexInvertCells_Internal(numCells, numCorners, cells);CHKERRQ(ierr);
3934     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3935     /* Set labels */
3936     for (v = 0; v < numVertices; ++v) {
3937       if (out->pointmarkerlist[v]) {
3938         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3939       }
3940     }
3941     if (interpolate) {
3942       PetscInt e, f;
3943 
3944       for (e = 0; e < out->numberofedges; e++) {
3945         if (out->edgemarkerlist[e]) {
3946           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3947           const PetscInt *edges;
3948           PetscInt        numEdges;
3949 
3950           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3951           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3952           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3953           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3954         }
3955       }
3956       for (f = 0; f < out->numberoftrifaces; f++) {
3957         if (out->trifacemarkerlist[f]) {
3958           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3959           const PetscInt *faces;
3960           PetscInt        numFaces;
3961 
3962           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3963           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3964           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3965           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3966         }
3967       }
3968     }
3969     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3970   }
3971   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3972   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3973   PetscFunctionReturn(0);
3974 }
3975 #endif
3976 
3977 #undef __FUNCT__
3978 #define __FUNCT__ "DMPlexGenerate"
3979 /*@C
3980   DMPlexGenerate - Generates a mesh.
3981 
3982   Not Collective
3983 
3984   Input Parameters:
3985 + boundary - The DMPlex boundary object
3986 . name - The mesh generation package name
3987 - interpolate - Flag to create intermediate mesh elements
3988 
3989   Output Parameter:
3990 . mesh - The DMPlex object
3991 
3992   Level: intermediate
3993 
3994 .keywords: mesh, elements
3995 .seealso: DMPlexCreate(), DMRefine()
3996 @*/
3997 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3998 {
3999   PetscInt       dim;
4000   char           genname[1024];
4001   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4002   PetscErrorCode ierr;
4003 
4004   PetscFunctionBegin;
4005   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4006   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4007   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4008   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4009   if (flg) name = genname;
4010   if (name) {
4011     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4012     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4013     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4014   }
4015   switch (dim) {
4016   case 1:
4017     if (!name || isTriangle) {
4018 #if defined(PETSC_HAVE_TRIANGLE)
4019       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4020 #else
4021       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4022 #endif
4023     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4024     break;
4025   case 2:
4026     if (!name || isCTetgen) {
4027 #if defined(PETSC_HAVE_CTETGEN)
4028       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4029 #else
4030       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4031 #endif
4032     } else if (isTetgen) {
4033 #if defined(PETSC_HAVE_TETGEN)
4034       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4035 #else
4036       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4037 #endif
4038     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4039     break;
4040   default:
4041     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4042   }
4043   PetscFunctionReturn(0);
4044 }
4045 
4046 typedef PetscInt CellRefiner;
4047 
4048 #undef __FUNCT__
4049 #define __FUNCT__ "GetDepthStart_Private"
4050 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4051 {
4052   PetscFunctionBegin;
4053   if (cStart) *cStart = 0;
4054   if (vStart) *vStart = depthSize[depth];
4055   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4056   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4057   PetscFunctionReturn(0);
4058 }
4059 
4060 #undef __FUNCT__
4061 #define __FUNCT__ "GetDepthEnd_Private"
4062 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4063 {
4064   PetscFunctionBegin;
4065   if (cEnd) *cEnd = depthSize[depth];
4066   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4067   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4068   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4069   PetscFunctionReturn(0);
4070 }
4071 
4072 #undef __FUNCT__
4073 #define __FUNCT__ "CellRefinerGetSizes"
4074 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4075 {
4076   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4077   PetscErrorCode ierr;
4078 
4079   PetscFunctionBegin;
4080   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4081   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4082   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4083   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4084   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4085   switch (refiner) {
4086   case 1:
4087     /* Simplicial 2D */
4088     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4089     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4090     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4091     break;
4092   case 3:
4093     /* Hybrid 2D */
4094     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4095     cMax = PetscMin(cEnd, cMax);
4096     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4097     fMax         = PetscMin(fEnd, fMax);
4098     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4099     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
4100     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4101     break;
4102   case 2:
4103     /* Hex 2D */
4104     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4105     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4106     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4107     break;
4108   default:
4109     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4110   }
4111   PetscFunctionReturn(0);
4112 }
4113 
4114 #undef __FUNCT__
4115 #define __FUNCT__ "CellRefinerSetConeSizes"
4116 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4117 {
4118   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4119   PetscErrorCode ierr;
4120 
4121   PetscFunctionBegin;
4122   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4123   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4124   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4125   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4126   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4127   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4128   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4129   switch (refiner) {
4130   case 1:
4131     /* Simplicial 2D */
4132     /* All cells have 3 faces */
4133     for (c = cStart; c < cEnd; ++c) {
4134       for (r = 0; r < 4; ++r) {
4135         const PetscInt newp = (c - cStart)*4 + r;
4136 
4137         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4138       }
4139     }
4140     /* Split faces have 2 vertices and the same cells as the parent */
4141     for (f = fStart; f < fEnd; ++f) {
4142       for (r = 0; r < 2; ++r) {
4143         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4144         PetscInt       size;
4145 
4146         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4147         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4148         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4149       }
4150     }
4151     /* Interior faces have 2 vertices and 2 cells */
4152     for (c = cStart; c < cEnd; ++c) {
4153       for (r = 0; r < 3; ++r) {
4154         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4155 
4156         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4157         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4158       }
4159     }
4160     /* Old vertices have identical supports */
4161     for (v = vStart; v < vEnd; ++v) {
4162       const PetscInt newp = vStartNew + (v - vStart);
4163       PetscInt       size;
4164 
4165       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4166       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4167     }
4168     /* Face vertices have 2 + cells*2 supports */
4169     for (f = fStart; f < fEnd; ++f) {
4170       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4171       PetscInt       size;
4172 
4173       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4174       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4175     }
4176     break;
4177   case 2:
4178     /* Hex 2D */
4179     /* All cells have 4 faces */
4180     for (c = cStart; c < cEnd; ++c) {
4181       for (r = 0; r < 4; ++r) {
4182         const PetscInt newp = (c - cStart)*4 + r;
4183 
4184         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4185       }
4186     }
4187     /* Split faces have 2 vertices and the same cells as the parent */
4188     for (f = fStart; f < fEnd; ++f) {
4189       for (r = 0; r < 2; ++r) {
4190         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4191         PetscInt       size;
4192 
4193         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4194         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4195         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4196       }
4197     }
4198     /* Interior faces have 2 vertices and 2 cells */
4199     for (c = cStart; c < cEnd; ++c) {
4200       for (r = 0; r < 4; ++r) {
4201         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4202 
4203         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4204         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4205       }
4206     }
4207     /* Old vertices have identical supports */
4208     for (v = vStart; v < vEnd; ++v) {
4209       const PetscInt newp = vStartNew + (v - vStart);
4210       PetscInt       size;
4211 
4212       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4213       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4214     }
4215     /* Face vertices have 2 + cells supports */
4216     for (f = fStart; f < fEnd; ++f) {
4217       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4218       PetscInt       size;
4219 
4220       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4221       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4222     }
4223     /* Cell vertices have 4 supports */
4224     for (c = cStart; c < cEnd; ++c) {
4225       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4226 
4227       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4228     }
4229     break;
4230   case 3:
4231     /* Hybrid 2D */
4232     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4233     cMax = PetscMin(cEnd, cMax);
4234     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4235     fMax = PetscMin(fEnd, fMax);
4236     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4237     /* Interior cells have 3 faces */
4238     for (c = cStart; c < cMax; ++c) {
4239       for (r = 0; r < 4; ++r) {
4240         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4241 
4242         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4243       }
4244     }
4245     /* Hybrid cells have 4 faces */
4246     for (c = cMax; c < cEnd; ++c) {
4247       for (r = 0; r < 2; ++r) {
4248         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4249 
4250         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4251       }
4252     }
4253     /* Interior split faces have 2 vertices and the same cells as the parent */
4254     for (f = fStart; f < fMax; ++f) {
4255       for (r = 0; r < 2; ++r) {
4256         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4257         PetscInt       size;
4258 
4259         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4260         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4261         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4262       }
4263     }
4264     /* Interior cell faces have 2 vertices and 2 cells */
4265     for (c = cStart; c < cMax; ++c) {
4266       for (r = 0; r < 3; ++r) {
4267         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4268 
4269         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4270         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4271       }
4272     }
4273     /* Hybrid faces have 2 vertices and the same cells */
4274     for (f = fMax; f < fEnd; ++f) {
4275       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4276       PetscInt       size;
4277 
4278       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4279       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4280       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4281     }
4282     /* Hybrid cell faces have 2 vertices and 2 cells */
4283     for (c = cMax; c < cEnd; ++c) {
4284       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4285 
4286       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4287       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4288     }
4289     /* Old vertices have identical supports */
4290     for (v = vStart; v < vEnd; ++v) {
4291       const PetscInt newp = vStartNew + (v - vStart);
4292       PetscInt       size;
4293 
4294       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4295       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4296     }
4297     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4298     for (f = fStart; f < fMax; ++f) {
4299       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4300       const PetscInt *support;
4301       PetscInt       size, newSize = 2, s;
4302 
4303       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4304       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4305       for (s = 0; s < size; ++s) {
4306         if (support[s] >= cMax) newSize += 1;
4307         else newSize += 2;
4308       }
4309       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4310     }
4311     break;
4312   default:
4313     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4314   }
4315   PetscFunctionReturn(0);
4316 }
4317 
4318 #undef __FUNCT__
4319 #define __FUNCT__ "CellRefinerSetCones"
4320 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4321 {
4322   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
4323   PetscInt       maxSupportSize, *supportRef;
4324   PetscErrorCode ierr;
4325 
4326   PetscFunctionBegin;
4327   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4328   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4329   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4330   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4331   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4332   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4333   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4334   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4335   switch (refiner) {
4336   case 1:
4337     /* Simplicial 2D */
4338     /*
4339      2
4340      |\
4341      | \
4342      |  \
4343      |   \
4344      | C  \
4345      |     \
4346      |      \
4347      2---1---1
4348      |\  D  / \
4349      | 2   0   \
4350      |A \ /  B  \
4351      0---0-------1
4352      */
4353     /* All cells have 3 faces */
4354     for (c = cStart; c < cEnd; ++c) {
4355       const PetscInt  newp = cStartNew + (c - cStart)*4;
4356       const PetscInt *cone, *ornt;
4357       PetscInt        coneNew[3], orntNew[3];
4358 
4359       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4360       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4361       /* A triangle */
4362       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4363       orntNew[0] = ornt[0];
4364       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4365       orntNew[1] = -2;
4366       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4367       orntNew[2] = ornt[2];
4368       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4369       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4370 #if 1
4371       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4372       for (p = 0; p < 3; ++p) {
4373         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4374       }
4375 #endif
4376       /* B triangle */
4377       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4378       orntNew[0] = ornt[0];
4379       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4380       orntNew[1] = ornt[1];
4381       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4382       orntNew[2] = -2;
4383       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4384       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4385 #if 1
4386       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4387       for (p = 0; p < 3; ++p) {
4388         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4389       }
4390 #endif
4391       /* C triangle */
4392       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4393       orntNew[0] = -2;
4394       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4395       orntNew[1] = ornt[1];
4396       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4397       orntNew[2] = ornt[2];
4398       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4399       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4400 #if 1
4401       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4402       for (p = 0; p < 3; ++p) {
4403         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4404       }
4405 #endif
4406       /* D triangle */
4407       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4408       orntNew[0] = 0;
4409       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4410       orntNew[1] = 0;
4411       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4412       orntNew[2] = 0;
4413       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4414       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4415 #if 1
4416       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4417       for (p = 0; p < 3; ++p) {
4418         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4419       }
4420 #endif
4421     }
4422     /* Split faces have 2 vertices and the same cells as the parent */
4423     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4424     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4425     for (f = fStart; f < fEnd; ++f) {
4426       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4427 
4428       for (r = 0; r < 2; ++r) {
4429         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4430         const PetscInt *cone, *support;
4431         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4432 
4433         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4434         coneNew[0]       = vStartNew + (cone[0] - vStart);
4435         coneNew[1]       = vStartNew + (cone[1] - vStart);
4436         coneNew[(r+1)%2] = newv;
4437         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4438 #if 1
4439         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4440         for (p = 0; p < 2; ++p) {
4441           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4442         }
4443 #endif
4444         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4445         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4446         for (s = 0; s < supportSize; ++s) {
4447           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4448           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4449           for (c = 0; c < coneSize; ++c) {
4450             if (cone[c] == f) break;
4451           }
4452           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4453         }
4454         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4455 #if 1
4456         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4457         for (p = 0; p < supportSize; ++p) {
4458           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4459         }
4460 #endif
4461       }
4462     }
4463     /* Interior faces have 2 vertices and 2 cells */
4464     for (c = cStart; c < cEnd; ++c) {
4465       const PetscInt *cone;
4466 
4467       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4468       for (r = 0; r < 3; ++r) {
4469         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4470         PetscInt       coneNew[2];
4471         PetscInt       supportNew[2];
4472 
4473         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4474         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4475         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4476 #if 1
4477         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4478         for (p = 0; p < 2; ++p) {
4479           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4480         }
4481 #endif
4482         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4483         supportNew[1] = (c - cStart)*4 + 3;
4484         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4485 #if 1
4486         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4487         for (p = 0; p < 2; ++p) {
4488           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4489         }
4490 #endif
4491       }
4492     }
4493     /* Old vertices have identical supports */
4494     for (v = vStart; v < vEnd; ++v) {
4495       const PetscInt  newp = vStartNew + (v - vStart);
4496       const PetscInt *support, *cone;
4497       PetscInt        size, s;
4498 
4499       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4500       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4501       for (s = 0; s < size; ++s) {
4502         PetscInt r = 0;
4503 
4504         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4505         if (cone[1] == v) r = 1;
4506         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4507       }
4508       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4509 #if 1
4510       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4511       for (p = 0; p < size; ++p) {
4512         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4513       }
4514 #endif
4515     }
4516     /* Face vertices have 2 + cells*2 supports */
4517     for (f = fStart; f < fEnd; ++f) {
4518       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4519       const PetscInt *cone, *support;
4520       PetscInt        size, s;
4521 
4522       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4523       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4524       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4525       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4526       for (s = 0; s < size; ++s) {
4527         PetscInt r = 0;
4528 
4529         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4530         if      (cone[1] == f) r = 1;
4531         else if (cone[2] == f) r = 2;
4532         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4533         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4534       }
4535       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4536 #if 1
4537       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4538       for (p = 0; p < 2+size*2; ++p) {
4539         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4540       }
4541 #endif
4542     }
4543     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4544     break;
4545   case 2:
4546     /* Hex 2D */
4547     /*
4548      3---------2---------2
4549      |         |         |
4550      |    D    2    C    |
4551      |         |         |
4552      3----3----0----1----1
4553      |         |         |
4554      |    A    0    B    |
4555      |         |         |
4556      0---------0---------1
4557      */
4558     /* All cells have 4 faces */
4559     for (c = cStart; c < cEnd; ++c) {
4560       const PetscInt  newp = (c - cStart)*4;
4561       const PetscInt *cone, *ornt;
4562       PetscInt        coneNew[4], orntNew[4];
4563 
4564       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4565       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4566       /* A quad */
4567       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4568       orntNew[0] = ornt[0];
4569       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4570       orntNew[1] = 0;
4571       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4572       orntNew[2] = -2;
4573       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4574       orntNew[3] = ornt[3];
4575       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4576       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4577 #if 1
4578       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4579       for (p = 0; p < 4; ++p) {
4580         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4581       }
4582 #endif
4583       /* B quad */
4584       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4585       orntNew[0] = ornt[0];
4586       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4587       orntNew[1] = ornt[1];
4588       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4589       orntNew[2] = 0;
4590       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4591       orntNew[3] = -2;
4592       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4593       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4594 #if 1
4595       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4596       for (p = 0; p < 4; ++p) {
4597         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4598       }
4599 #endif
4600       /* C quad */
4601       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4602       orntNew[0] = -2;
4603       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4604       orntNew[1] = ornt[1];
4605       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4606       orntNew[2] = ornt[2];
4607       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4608       orntNew[3] = 0;
4609       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4610       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4611 #if 1
4612       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4613       for (p = 0; p < 4; ++p) {
4614         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4615       }
4616 #endif
4617       /* D quad */
4618       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4619       orntNew[0] = 0;
4620       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4621       orntNew[1] = -2;
4622       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4623       orntNew[2] = ornt[2];
4624       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4625       orntNew[3] = ornt[3];
4626       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4627       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4628 #if 1
4629       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4630       for (p = 0; p < 4; ++p) {
4631         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4632       }
4633 #endif
4634     }
4635     /* Split faces have 2 vertices and the same cells as the parent */
4636     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4637     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4638     for (f = fStart; f < fEnd; ++f) {
4639       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4640 
4641       for (r = 0; r < 2; ++r) {
4642         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4643         const PetscInt *cone, *support;
4644         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4645 
4646         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4647         coneNew[0]       = vStartNew + (cone[0] - vStart);
4648         coneNew[1]       = vStartNew + (cone[1] - vStart);
4649         coneNew[(r+1)%2] = newv;
4650         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4651 #if 1
4652         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4653         for (p = 0; p < 2; ++p) {
4654           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4655         }
4656 #endif
4657         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4658         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4659         for (s = 0; s < supportSize; ++s) {
4660           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4661           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4662           for (c = 0; c < coneSize; ++c) {
4663             if (cone[c] == f) break;
4664           }
4665           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4666         }
4667         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4668 #if 1
4669         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4670         for (p = 0; p < supportSize; ++p) {
4671           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4672         }
4673 #endif
4674       }
4675     }
4676     /* Interior faces have 2 vertices and 2 cells */
4677     for (c = cStart; c < cEnd; ++c) {
4678       const PetscInt *cone;
4679       PetscInt        coneNew[2], supportNew[2];
4680 
4681       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4682       for (r = 0; r < 4; ++r) {
4683         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4684 
4685         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4686         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4687         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4688 #if 1
4689         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4690         for (p = 0; p < 2; ++p) {
4691           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4692         }
4693 #endif
4694         supportNew[0] = (c - cStart)*4 + r;
4695         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4696         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4697 #if 1
4698         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4699         for (p = 0; p < 2; ++p) {
4700           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4701         }
4702 #endif
4703       }
4704     }
4705     /* Old vertices have identical supports */
4706     for (v = vStart; v < vEnd; ++v) {
4707       const PetscInt  newp = vStartNew + (v - vStart);
4708       const PetscInt *support, *cone;
4709       PetscInt        size, s;
4710 
4711       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4712       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4713       for (s = 0; s < size; ++s) {
4714         PetscInt r = 0;
4715 
4716         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4717         if (cone[1] == v) r = 1;
4718         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4719       }
4720       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4721 #if 1
4722       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4723       for (p = 0; p < size; ++p) {
4724         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4725       }
4726 #endif
4727     }
4728     /* Face vertices have 2 + cells supports */
4729     for (f = fStart; f < fEnd; ++f) {
4730       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4731       const PetscInt *cone, *support;
4732       PetscInt        size, s;
4733 
4734       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4735       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4736       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4737       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4738       for (s = 0; s < size; ++s) {
4739         PetscInt r = 0;
4740 
4741         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4742         if      (cone[1] == f) r = 1;
4743         else if (cone[2] == f) r = 2;
4744         else if (cone[3] == f) r = 3;
4745         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4746       }
4747       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4748 #if 1
4749       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4750       for (p = 0; p < 2+size; ++p) {
4751         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4752       }
4753 #endif
4754     }
4755     /* Cell vertices have 4 supports */
4756     for (c = cStart; c < cEnd; ++c) {
4757       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4758       PetscInt       supportNew[4];
4759 
4760       for (r = 0; r < 4; ++r) {
4761         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4762       }
4763       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4764     }
4765     break;
4766   case 3:
4767     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4768     cMax = PetscMin(cEnd, cMax);
4769     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4770     fMax = PetscMin(fEnd, fMax);
4771     /* Interior cells have 3 faces */
4772     for (c = cStart; c < cMax; ++c) {
4773       const PetscInt  newp = cStartNew + (c - cStart)*4;
4774       const PetscInt *cone, *ornt;
4775       PetscInt        coneNew[3], orntNew[3];
4776 
4777       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4778       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4779       /* A triangle */
4780       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4781       orntNew[0] = ornt[0];
4782       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4783       orntNew[1] = -2;
4784       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4785       orntNew[2] = ornt[2];
4786       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4787       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4788 #if 1
4789       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4790       for (p = 0; p < 3; ++p) {
4791         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4792       }
4793 #endif
4794       /* B triangle */
4795       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4796       orntNew[0] = ornt[0];
4797       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4798       orntNew[1] = ornt[1];
4799       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4800       orntNew[2] = -2;
4801       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4802       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4803 #if 1
4804       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4805       for (p = 0; p < 3; ++p) {
4806         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4807       }
4808 #endif
4809       /* C triangle */
4810       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4811       orntNew[0] = -2;
4812       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4813       orntNew[1] = ornt[1];
4814       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4815       orntNew[2] = ornt[2];
4816       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4817       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4818 #if 1
4819       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4820       for (p = 0; p < 3; ++p) {
4821         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4822       }
4823 #endif
4824       /* D triangle */
4825       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4826       orntNew[0] = 0;
4827       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4828       orntNew[1] = 0;
4829       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4830       orntNew[2] = 0;
4831       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4832       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4833 #if 1
4834       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4835       for (p = 0; p < 3; ++p) {
4836         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4837       }
4838 #endif
4839     }
4840     /*
4841      2----3----3
4842      |         |
4843      |    B    |
4844      |         |
4845      0----4--- 1
4846      |         |
4847      |    A    |
4848      |         |
4849      0----2----1
4850      */
4851     /* Hybrid cells have 4 faces */
4852     for (c = cMax; c < cEnd; ++c) {
4853       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4854       const PetscInt *cone, *ornt;
4855       PetscInt        coneNew[4], orntNew[4];
4856 
4857       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4858       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4859       /* A quad */
4860       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4861       orntNew[0] = ornt[0];
4862       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4863       orntNew[1] = ornt[1];
4864       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4865       orntNew[2] = 0;
4866       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4867       orntNew[3] = 0;
4868       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4869       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4870 #if 1
4871       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4872       for (p = 0; p < 4; ++p) {
4873         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4874       }
4875 #endif
4876       /* B quad */
4877       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4878       orntNew[0] = ornt[0];
4879       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4880       orntNew[1] = ornt[1];
4881       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4882       orntNew[2] = 0;
4883       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4884       orntNew[3] = 0;
4885       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4886       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4887 #if 1
4888       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4889       for (p = 0; p < 4; ++p) {
4890         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4891       }
4892 #endif
4893     }
4894     /* Interior split faces have 2 vertices and the same cells as the parent */
4895     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4896     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4897     for (f = fStart; f < fMax; ++f) {
4898       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4899 
4900       for (r = 0; r < 2; ++r) {
4901         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4902         const PetscInt *cone, *support;
4903         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4904 
4905         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4906         coneNew[0]       = vStartNew + (cone[0] - vStart);
4907         coneNew[1]       = vStartNew + (cone[1] - vStart);
4908         coneNew[(r+1)%2] = newv;
4909         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4910 #if 1
4911         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4912         for (p = 0; p < 2; ++p) {
4913           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4914         }
4915 #endif
4916         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4917         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4918         for (s = 0; s < supportSize; ++s) {
4919           if (support[s] >= cMax) {
4920             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4921           } else {
4922             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4923             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4924             for (c = 0; c < coneSize; ++c) {
4925               if (cone[c] == f) break;
4926             }
4927             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4928           }
4929         }
4930         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4931 #if 1
4932         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4933         for (p = 0; p < supportSize; ++p) {
4934           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4935         }
4936 #endif
4937       }
4938     }
4939     /* Interior cell faces have 2 vertices and 2 cells */
4940     for (c = cStart; c < cMax; ++c) {
4941       const PetscInt *cone;
4942 
4943       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4944       for (r = 0; r < 3; ++r) {
4945         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4946         PetscInt       coneNew[2];
4947         PetscInt       supportNew[2];
4948 
4949         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4950         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4951         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4952 #if 1
4953         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4954         for (p = 0; p < 2; ++p) {
4955           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4956         }
4957 #endif
4958         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4959         supportNew[1] = (c - cStart)*4 + 3;
4960         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4961 #if 1
4962         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4963         for (p = 0; p < 2; ++p) {
4964           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4965         }
4966 #endif
4967       }
4968     }
4969     /* Interior hybrid faces have 2 vertices and the same cells */
4970     for (f = fMax; f < fEnd; ++f) {
4971       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4972       const PetscInt *cone;
4973       const PetscInt *support;
4974       PetscInt        coneNew[2];
4975       PetscInt        supportNew[2];
4976       PetscInt        size, s, r;
4977 
4978       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4979       coneNew[0] = vStartNew + (cone[0] - vStart);
4980       coneNew[1] = vStartNew + (cone[1] - vStart);
4981       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4982 #if 1
4983       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4984       for (p = 0; p < 2; ++p) {
4985         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4986       }
4987 #endif
4988       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4989       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4990       for (s = 0; s < size; ++s) {
4991         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4992         for (r = 0; r < 2; ++r) {
4993           if (cone[r+2] == f) break;
4994         }
4995         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4996       }
4997       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4998 #if 1
4999       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5000       for (p = 0; p < size; ++p) {
5001         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5002       }
5003 #endif
5004     }
5005     /* Cell hybrid faces have 2 vertices and 2 cells */
5006     for (c = cMax; c < cEnd; ++c) {
5007       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5008       const PetscInt *cone;
5009       PetscInt        coneNew[2];
5010       PetscInt        supportNew[2];
5011 
5012       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5013       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5014       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5015       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5016 #if 1
5017       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5018       for (p = 0; p < 2; ++p) {
5019         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5020       }
5021 #endif
5022       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5023       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5024       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5025 #if 1
5026       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5027       for (p = 0; p < 2; ++p) {
5028         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5029       }
5030 #endif
5031     }
5032     /* Old vertices have identical supports */
5033     for (v = vStart; v < vEnd; ++v) {
5034       const PetscInt  newp = vStartNew + (v - vStart);
5035       const PetscInt *support, *cone;
5036       PetscInt        size, s;
5037 
5038       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5039       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5040       for (s = 0; s < size; ++s) {
5041         if (support[s] >= fMax) {
5042           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5043         } else {
5044           PetscInt r = 0;
5045 
5046           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5047           if (cone[1] == v) r = 1;
5048           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5049         }
5050       }
5051       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5052 #if 1
5053       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5054       for (p = 0; p < size; ++p) {
5055         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5056       }
5057 #endif
5058     }
5059     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5060     for (f = fStart; f < fMax; ++f) {
5061       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5062       const PetscInt *cone, *support;
5063       PetscInt        size, newSize = 2, s;
5064 
5065       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5066       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5067       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5068       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5069       for (s = 0; s < size; ++s) {
5070         PetscInt r = 0;
5071 
5072         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5073         if (support[s] >= cMax) {
5074           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5075 
5076           newSize += 1;
5077         } else {
5078           if      (cone[1] == f) r = 1;
5079           else if (cone[2] == f) r = 2;
5080           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5081           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5082 
5083           newSize += 2;
5084         }
5085       }
5086       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5087 #if 1
5088       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5089       for (p = 0; p < newSize; ++p) {
5090         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5091       }
5092 #endif
5093     }
5094     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5095     break;
5096   default:
5097     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5098   }
5099   PetscFunctionReturn(0);
5100 }
5101 
5102 #undef __FUNCT__
5103 #define __FUNCT__ "CellRefinerSetCoordinates"
5104 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5105 {
5106   PetscSection   coordSection, coordSectionNew;
5107   Vec            coordinates, coordinatesNew;
5108   PetscScalar   *coords, *coordsNew;
5109   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5110   PetscErrorCode ierr;
5111 
5112   PetscFunctionBegin;
5113   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5114   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5115   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5116   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5117   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5118   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5119   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5120   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5121   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5122   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5123   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5124   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5125   if (fMax < 0) fMax = fEnd;
5126   switch (refiner) {
5127   case 1:
5128   case 2:
5129   case 3:
5130     /* Simplicial and Hex 2D */
5131     /* All vertices have the dim coordinates */
5132     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5133       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5134       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5135     }
5136     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5137     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5138     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5139     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5140     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5141     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5142     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5143     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5144     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5145     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5146     /* Old vertices have the same coordinates */
5147     for (v = vStart; v < vEnd; ++v) {
5148       const PetscInt newv = vStartNew + (v - vStart);
5149       PetscInt       off, offnew, d;
5150 
5151       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5152       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5153       for (d = 0; d < dim; ++d) {
5154         coordsNew[offnew+d] = coords[off+d];
5155       }
5156     }
5157     /* Face vertices have the average of endpoint coordinates */
5158     for (f = fStart; f < fMax; ++f) {
5159       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5160       const PetscInt *cone;
5161       PetscInt        coneSize, offA, offB, offnew, d;
5162 
5163       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5164       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5165       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5166       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5167       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5168       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5169       for (d = 0; d < dim; ++d) {
5170         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5171       }
5172     }
5173     /* Just Hex 2D */
5174     if (refiner == 2) {
5175       /* Cell vertices have the average of corner coordinates */
5176       for (c = cStart; c < cEnd; ++c) {
5177         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5178         PetscInt      *cone = NULL;
5179         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5180 
5181         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5182         for (p = 0; p < closureSize*2; p += 2) {
5183           const PetscInt point = cone[p];
5184           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5185         }
5186         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5187         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5188         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5189         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5190         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5191         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5192         for (d = 0; d < dim; ++d) {
5193           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5194         }
5195         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5196       }
5197     }
5198     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5199     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5200     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5201     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5202     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5203     break;
5204   default:
5205     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5206   }
5207   PetscFunctionReturn(0);
5208 }
5209 
5210 #undef __FUNCT__
5211 #define __FUNCT__ "DMPlexCreateProcessSF"
5212 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5213 {
5214   PetscInt           numRoots, numLeaves, l;
5215   const PetscInt    *localPoints;
5216   const PetscSFNode *remotePoints;
5217   PetscInt          *localPointsNew;
5218   PetscSFNode       *remotePointsNew;
5219   PetscInt          *ranks, *ranksNew;
5220   PetscErrorCode     ierr;
5221 
5222   PetscFunctionBegin;
5223   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5224   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5225   for (l = 0; l < numLeaves; ++l) {
5226     ranks[l] = remotePoints[l].rank;
5227   }
5228   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5229   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5230   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5231   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5232   for (l = 0; l < numLeaves; ++l) {
5233     ranksNew[l]              = ranks[l];
5234     localPointsNew[l]        = l;
5235     remotePointsNew[l].index = 0;
5236     remotePointsNew[l].rank  = ranksNew[l];
5237   }
5238   ierr = PetscFree(ranks);CHKERRQ(ierr);
5239   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5240   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5241   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5242   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5243   PetscFunctionReturn(0);
5244 }
5245 
5246 #undef __FUNCT__
5247 #define __FUNCT__ "CellRefinerCreateSF"
5248 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5249 {
5250   PetscSF            sf, sfNew, sfProcess;
5251   IS                 processRanks;
5252   MPI_Datatype       depthType;
5253   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5254   const PetscInt    *localPoints, *neighbors;
5255   const PetscSFNode *remotePoints;
5256   PetscInt          *localPointsNew;
5257   PetscSFNode       *remotePointsNew;
5258   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5259   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5260   PetscErrorCode     ierr;
5261 
5262   PetscFunctionBegin;
5263   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5264   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5265   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5266   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5267   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5268   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5269   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5270   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5271   switch (refiner) {
5272   case 3:
5273     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5274     cMax = PetscMin(cEnd, cMax);
5275     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5276     fMax = PetscMin(fEnd, fMax);
5277   }
5278   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5279   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5280   /* Caculate size of new SF */
5281   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5282   if (numRoots < 0) PetscFunctionReturn(0);
5283   for (l = 0; l < numLeaves; ++l) {
5284     const PetscInt p = localPoints[l];
5285 
5286     switch (refiner) {
5287     case 1:
5288       /* Simplicial 2D */
5289       if ((p >= vStart) && (p < vEnd)) {
5290         /* Old vertices stay the same */
5291         ++numLeavesNew;
5292       } else if ((p >= fStart) && (p < fEnd)) {
5293         /* Old faces add new faces and vertex */
5294         numLeavesNew += 1 + 2;
5295       } else if ((p >= cStart) && (p < cEnd)) {
5296         /* Old cells add new cells and interior faces */
5297         numLeavesNew += 4 + 3;
5298       }
5299       break;
5300     case 2:
5301       /* Hex 2D */
5302       if ((p >= vStart) && (p < vEnd)) {
5303         /* Old vertices stay the same */
5304         ++numLeavesNew;
5305       } else if ((p >= fStart) && (p < fEnd)) {
5306         /* Old faces add new faces and vertex */
5307         numLeavesNew += 1 + 2;
5308       } else if ((p >= cStart) && (p < cEnd)) {
5309         /* Old cells add new cells and interior faces */
5310         numLeavesNew += 4 + 4;
5311       }
5312       break;
5313     default:
5314       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5315     }
5316   }
5317   /* Communicate depthSizes for each remote rank */
5318   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5319   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5320   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5321   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
5322   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5323   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5324   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5325   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5326   for (n = 0; n < numNeighbors; ++n) {
5327     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5328   }
5329   depthSizeOld[depth]   = cMax;
5330   depthSizeOld[0]       = vMax;
5331   depthSizeOld[depth-1] = fMax;
5332   depthSizeOld[1]       = eMax;
5333 
5334   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5335   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5336 
5337   depthSizeOld[depth]   = cEnd - cStart;
5338   depthSizeOld[0]       = vEnd - vStart;
5339   depthSizeOld[depth-1] = fEnd - fStart;
5340   depthSizeOld[1]       = eEnd - eStart;
5341 
5342   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5343   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5344   for (n = 0; n < numNeighbors; ++n) {
5345     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5346   }
5347   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5348   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5349   /* Calculate new point SF */
5350   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5351   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5352   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5353   for (l = 0, m = 0; l < numLeaves; ++l) {
5354     PetscInt    p     = localPoints[l];
5355     PetscInt    rp    = remotePoints[l].index, n;
5356     PetscMPIInt rrank = remotePoints[l].rank;
5357 
5358     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5359     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5360     switch (refiner) {
5361     case 1:
5362       /* Simplicial 2D */
5363       if ((p >= vStart) && (p < vEnd)) {
5364         /* Old vertices stay the same */
5365         localPointsNew[m]        = vStartNew     + (p  - vStart);
5366         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5367         remotePointsNew[m].rank  = rrank;
5368         ++m;
5369       } else if ((p >= fStart) && (p < fEnd)) {
5370         /* Old faces add new faces and vertex */
5371         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5372         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5373         remotePointsNew[m].rank  = rrank;
5374         ++m;
5375         for (r = 0; r < 2; ++r, ++m) {
5376           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5377           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5378           remotePointsNew[m].rank  = rrank;
5379         }
5380       } else if ((p >= cStart) && (p < cEnd)) {
5381         /* Old cells add new cells and interior faces */
5382         for (r = 0; r < 4; ++r, ++m) {
5383           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5384           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5385           remotePointsNew[m].rank  = rrank;
5386         }
5387         for (r = 0; r < 3; ++r, ++m) {
5388           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5389           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5390           remotePointsNew[m].rank  = rrank;
5391         }
5392       }
5393       break;
5394     case 2:
5395       /* Hex 2D */
5396       if ((p >= vStart) && (p < vEnd)) {
5397         /* Old vertices stay the same */
5398         localPointsNew[m]        = vStartNew     + (p  - vStart);
5399         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5400         remotePointsNew[m].rank  = rrank;
5401         ++m;
5402       } else if ((p >= fStart) && (p < fEnd)) {
5403         /* Old faces add new faces and vertex */
5404         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5405         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5406         remotePointsNew[m].rank  = rrank;
5407         ++m;
5408         for (r = 0; r < 2; ++r, ++m) {
5409           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5410           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5411           remotePointsNew[m].rank  = rrank;
5412         }
5413       } else if ((p >= cStart) && (p < cEnd)) {
5414         /* Old cells add new cells and interior faces */
5415         for (r = 0; r < 4; ++r, ++m) {
5416           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5417           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5418           remotePointsNew[m].rank  = rrank;
5419         }
5420         for (r = 0; r < 4; ++r, ++m) {
5421           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5422           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5423           remotePointsNew[m].rank  = rrank;
5424         }
5425       }
5426       break;
5427     case 3:
5428       /* Hybrid simplicial 2D */
5429       if ((p >= vStart) && (p < vEnd)) {
5430         /* Old vertices stay the same */
5431         localPointsNew[m]        = vStartNew     + (p  - vStart);
5432         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5433         remotePointsNew[m].rank  = rrank;
5434         ++m;
5435       } else if ((p >= fStart) && (p < fMax)) {
5436         /* Old interior faces add new faces and vertex */
5437         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5438         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5439         remotePointsNew[m].rank  = rrank;
5440         ++m;
5441         for (r = 0; r < 2; ++r, ++m) {
5442           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5443           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5444           remotePointsNew[m].rank  = rrank;
5445         }
5446       } else if ((p >= fMax) && (p < fEnd)) {
5447         /* Old hybrid faces stay the same */
5448         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5449         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5450         remotePointsNew[m].rank  = rrank;
5451         ++m;
5452       } else if ((p >= cStart) && (p < cMax)) {
5453         /* Old interior cells add new cells and interior faces */
5454         for (r = 0; r < 4; ++r, ++m) {
5455           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5456           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5457           remotePointsNew[m].rank  = rrank;
5458         }
5459         for (r = 0; r < 3; ++r, ++m) {
5460           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5461           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5462           remotePointsNew[m].rank  = rrank;
5463         }
5464       } else if ((p >= cStart) && (p < cMax)) {
5465         /* Old hybrid cells add new cells and hybrid face */
5466         for (r = 0; r < 2; ++r, ++m) {
5467           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5468           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5469           remotePointsNew[m].rank  = rrank;
5470         }
5471         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5472         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5473         remotePointsNew[m].rank  = rrank;
5474         ++m;
5475       }
5476       break;
5477     default:
5478       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5479     }
5480   }
5481   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5482   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5483   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5484   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5485   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5486   PetscFunctionReturn(0);
5487 }
5488 
5489 #undef __FUNCT__
5490 #define __FUNCT__ "CellRefinerCreateLabels"
5491 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5492 {
5493   PetscInt       numLabels, l;
5494   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5495   PetscErrorCode ierr;
5496 
5497   PetscFunctionBegin;
5498   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5499   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5500   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5501   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5502 
5503   cStartNew = 0;
5504   vStartNew = depthSize[2];
5505   fStartNew = depthSize[2] + depthSize[0];
5506 
5507   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5508   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5509   switch (refiner) {
5510   case 3:
5511     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5512     cMax = PetscMin(cEnd, cMax);
5513     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5514     fMax = PetscMin(fEnd, fMax);
5515   }
5516   for (l = 0; l < numLabels; ++l) {
5517     DMLabel         label, labelNew;
5518     const char     *lname;
5519     PetscBool       isDepth;
5520     IS              valueIS;
5521     const PetscInt *values;
5522     PetscInt        numValues, val;
5523 
5524     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5525     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5526     if (isDepth) continue;
5527     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5528     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5529     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5530     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5531     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5532     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5533     for (val = 0; val < numValues; ++val) {
5534       IS              pointIS;
5535       const PetscInt *points;
5536       PetscInt        numPoints, n;
5537 
5538       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5539       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5540       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5541       for (n = 0; n < numPoints; ++n) {
5542         const PetscInt p = points[n];
5543         switch (refiner) {
5544         case 1:
5545           /* Simplicial 2D */
5546           if ((p >= vStart) && (p < vEnd)) {
5547             /* Old vertices stay the same */
5548             newp = vStartNew + (p - vStart);
5549             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5550           } else if ((p >= fStart) && (p < fEnd)) {
5551             /* Old faces add new faces and vertex */
5552             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5553             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5554             for (r = 0; r < 2; ++r) {
5555               newp = fStartNew + (p - fStart)*2 + r;
5556               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5557             }
5558           } else if ((p >= cStart) && (p < cEnd)) {
5559             /* Old cells add new cells and interior faces */
5560             for (r = 0; r < 4; ++r) {
5561               newp = cStartNew + (p - cStart)*4 + r;
5562               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5563             }
5564             for (r = 0; r < 3; ++r) {
5565               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5566               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5567             }
5568           }
5569           break;
5570         case 2:
5571           /* Hex 2D */
5572           if ((p >= vStart) && (p < vEnd)) {
5573             /* Old vertices stay the same */
5574             newp = vStartNew + (p - vStart);
5575             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5576           } else if ((p >= fStart) && (p < fEnd)) {
5577             /* Old faces add new faces and vertex */
5578             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5579             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5580             for (r = 0; r < 2; ++r) {
5581               newp = fStartNew + (p - fStart)*2 + r;
5582               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5583             }
5584           } else if ((p >= cStart) && (p < cEnd)) {
5585             /* Old cells add new cells and interior faces and vertex */
5586             for (r = 0; r < 4; ++r) {
5587               newp = cStartNew + (p - cStart)*4 + r;
5588               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5589             }
5590             for (r = 0; r < 4; ++r) {
5591               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5592               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5593             }
5594             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5595             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5596           }
5597           break;
5598         case 3:
5599           /* Hybrid simplicial 2D */
5600           if ((p >= vStart) && (p < vEnd)) {
5601             /* Old vertices stay the same */
5602             newp = vStartNew + (p - vStart);
5603             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5604           } else if ((p >= fStart) && (p < fMax)) {
5605             /* Old interior faces add new faces and vertex */
5606             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5607             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5608             for (r = 0; r < 2; ++r) {
5609               newp = fStartNew + (p - fStart)*2 + r;
5610               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5611             }
5612           } else if ((p >= fMax) && (p < fEnd)) {
5613             /* Old hybrid faces stay the same */
5614             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5615             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5616           } else if ((p >= cStart) && (p < cMax)) {
5617             /* Old interior cells add new cells and interior faces */
5618             for (r = 0; r < 4; ++r) {
5619               newp = cStartNew + (p - cStart)*4 + r;
5620               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5621             }
5622             for (r = 0; r < 3; ++r) {
5623               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5624               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5625             }
5626           } else if ((p >= cMax) && (p < cEnd)) {
5627             /* Old hybrid cells add new cells and hybrid face */
5628             for (r = 0; r < 2; ++r) {
5629               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5630               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5631             }
5632             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5633             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5634           }
5635           break;
5636         default:
5637           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5638         }
5639       }
5640       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5641       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5642     }
5643     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5644     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5645     if (0) {
5646       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5647       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5648       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5649     }
5650   }
5651   PetscFunctionReturn(0);
5652 }
5653 
5654 #undef __FUNCT__
5655 #define __FUNCT__ "DMPlexRefine_Uniform"
5656 /* This will only work for interpolated meshes */
5657 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5658 {
5659   DM             rdm;
5660   PetscInt      *depthSize;
5661   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5662   PetscErrorCode ierr;
5663 
5664   PetscFunctionBegin;
5665   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5666   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5667   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5668   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5669   /* Calculate number of new points of each depth */
5670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5672   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5673   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5674   /* Step 1: Set chart */
5675   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5676   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5677   /* Step 2: Set cone/support sizes */
5678   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5679   /* Step 3: Setup refined DM */
5680   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5681   /* Step 4: Set cones and supports */
5682   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5683   /* Step 5: Stratify */
5684   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5685   /* Step 6: Set coordinates for vertices */
5686   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5687   /* Step 7: Create pointSF */
5688   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5689   /* Step 8: Create labels */
5690   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5691   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5692 
5693   *dmRefined = rdm;
5694   PetscFunctionReturn(0);
5695 }
5696 
5697 #undef __FUNCT__
5698 #define __FUNCT__ "DMPlexSetRefinementUniform"
5699 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5700 {
5701   DM_Plex *mesh = (DM_Plex*) dm->data;
5702 
5703   PetscFunctionBegin;
5704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5705   mesh->refinementUniform = refinementUniform;
5706   PetscFunctionReturn(0);
5707 }
5708 
5709 #undef __FUNCT__
5710 #define __FUNCT__ "DMPlexGetRefinementUniform"
5711 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5712 {
5713   DM_Plex *mesh = (DM_Plex*) dm->data;
5714 
5715   PetscFunctionBegin;
5716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5717   PetscValidPointer(refinementUniform,  2);
5718   *refinementUniform = mesh->refinementUniform;
5719   PetscFunctionReturn(0);
5720 }
5721 
5722 #undef __FUNCT__
5723 #define __FUNCT__ "DMPlexSetRefinementLimit"
5724 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5725 {
5726   DM_Plex *mesh = (DM_Plex*) dm->data;
5727 
5728   PetscFunctionBegin;
5729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5730   mesh->refinementLimit = refinementLimit;
5731   PetscFunctionReturn(0);
5732 }
5733 
5734 #undef __FUNCT__
5735 #define __FUNCT__ "DMPlexGetRefinementLimit"
5736 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5737 {
5738   DM_Plex *mesh = (DM_Plex*) dm->data;
5739 
5740   PetscFunctionBegin;
5741   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5742   PetscValidPointer(refinementLimit,  2);
5743   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5744   *refinementLimit = mesh->refinementLimit;
5745   PetscFunctionReturn(0);
5746 }
5747 
5748 #undef __FUNCT__
5749 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5750 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5751 {
5752   PetscInt       dim, cStart, coneSize, cMax;
5753   PetscErrorCode ierr;
5754 
5755   PetscFunctionBegin;
5756   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5757   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5758   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5759   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5760   switch (dim) {
5761   case 2:
5762     switch (coneSize) {
5763     case 3:
5764       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5765       else *cellRefiner = 1; /* Triangular */
5766       break;
5767     case 4:
5768       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5769       else *cellRefiner = 2; /* Quadrilateral */
5770       break;
5771     default:
5772       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5773     }
5774     break;
5775   default:
5776     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5777   }
5778   PetscFunctionReturn(0);
5779 }
5780 
5781 #undef __FUNCT__
5782 #define __FUNCT__ "DMRefine_Plex"
5783 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5784 {
5785   PetscReal      refinementLimit;
5786   PetscInt       dim, cStart, cEnd;
5787   char           genname[1024], *name = NULL;
5788   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5789   PetscErrorCode ierr;
5790 
5791   PetscFunctionBegin;
5792   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5793   if (isUniform) {
5794     CellRefiner cellRefiner;
5795 
5796     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5797     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5798     PetscFunctionReturn(0);
5799   }
5800   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5801   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5802   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5803   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5804   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5805   if (flg) name = genname;
5806   if (name) {
5807     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5808     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5809     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5810   }
5811   switch (dim) {
5812   case 2:
5813     if (!name || isTriangle) {
5814 #if defined(PETSC_HAVE_TRIANGLE)
5815       double  *maxVolumes;
5816       PetscInt c;
5817 
5818       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5819       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5820       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5821 #else
5822       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5823 #endif
5824     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5825     break;
5826   case 3:
5827     if (!name || isCTetgen) {
5828 #if defined(PETSC_HAVE_CTETGEN)
5829       PetscReal *maxVolumes;
5830       PetscInt   c;
5831 
5832       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5833       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5834       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5835 #else
5836       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5837 #endif
5838     } else if (isTetgen) {
5839 #if defined(PETSC_HAVE_TETGEN)
5840       double  *maxVolumes;
5841       PetscInt c;
5842 
5843       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5844       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5845       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5846 #else
5847       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5848 #endif
5849     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5850     break;
5851   default:
5852     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5853   }
5854   PetscFunctionReturn(0);
5855 }
5856 
5857 #undef __FUNCT__
5858 #define __FUNCT__ "DMPlexGetDepthLabel"
5859 /*@
5860   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
5861 
5862   Not Collective
5863 
5864   Input Parameter:
5865 . dm    - The DMPlex object
5866 
5867   Output Parameter:
5868 . depthLabel - The DMLabel recording point depth
5869 
5870   Level: developer
5871 
5872 .keywords: mesh, points
5873 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5874 @*/
5875 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
5876 {
5877   DM_Plex       *mesh = (DM_Plex*) dm->data;
5878   PetscErrorCode ierr;
5879 
5880   PetscFunctionBegin;
5881   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5882   PetscValidPointer(depthLabel, 2);
5883   if (!mesh->depthLabel) {
5884     ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);
5885   }
5886   *depthLabel = mesh->depthLabel;
5887   PetscFunctionReturn(0);
5888 }
5889 
5890 #undef __FUNCT__
5891 #define __FUNCT__ "DMPlexGetDepth"
5892 /*@
5893   DMPlexGetDepth - Get the depth of the DAG representing this mesh
5894 
5895   Not Collective
5896 
5897   Input Parameter:
5898 . dm    - The DMPlex object
5899 
5900   Output Parameter:
5901 . depth - The number of strata (breadth first levels) in the DAG
5902 
5903   Level: developer
5904 
5905 .keywords: mesh, points
5906 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5907 @*/
5908 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5909 {
5910   DMLabel        label;
5911   PetscInt       d = 0;
5912   PetscErrorCode ierr;
5913 
5914   PetscFunctionBegin;
5915   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5916   PetscValidPointer(depth, 2);
5917   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5918   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
5919   *depth = d-1;
5920   PetscFunctionReturn(0);
5921 }
5922 
5923 #undef __FUNCT__
5924 #define __FUNCT__ "DMPlexGetDepthStratum"
5925 /*@
5926   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5927 
5928   Not Collective
5929 
5930   Input Parameters:
5931 + dm           - The DMPlex object
5932 - stratumValue - The requested depth
5933 
5934   Output Parameters:
5935 + start - The first point at this depth
5936 - end   - One beyond the last point at this depth
5937 
5938   Level: developer
5939 
5940 .keywords: mesh, points
5941 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5942 @*/
5943 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5944 {
5945   DMLabel        label;
5946   PetscInt       depth;
5947   PetscErrorCode ierr;
5948 
5949   PetscFunctionBegin;
5950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5951   if (stratumValue < 0) {
5952     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5953     PetscFunctionReturn(0);
5954   } else {
5955     PetscInt pStart, pEnd;
5956 
5957     if (start) *start = 0;
5958     if (end)   *end   = 0;
5959     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5960     if (pStart == pEnd) PetscFunctionReturn(0);
5961   }
5962   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5963   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5964   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5965   depth = stratumValue;
5966   if ((depth < 0) || (depth >= label->numStrata)) {
5967     if (start) *start = 0;
5968     if (end)   *end   = 0;
5969   } else {
5970     if (start) *start = label->points[label->stratumOffsets[depth]];
5971     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
5972   }
5973   PetscFunctionReturn(0);
5974 }
5975 
5976 #undef __FUNCT__
5977 #define __FUNCT__ "DMPlexGetHeightStratum"
5978 /*@
5979   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5980 
5981   Not Collective
5982 
5983   Input Parameters:
5984 + dm           - The DMPlex object
5985 - stratumValue - The requested height
5986 
5987   Output Parameters:
5988 + start - The first point at this height
5989 - end   - One beyond the last point at this height
5990 
5991   Level: developer
5992 
5993 .keywords: mesh, points
5994 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5995 @*/
5996 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5997 {
5998   DMLabel        label;
5999   PetscInt       depth;
6000   PetscErrorCode ierr;
6001 
6002   PetscFunctionBegin;
6003   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6004   if (stratumValue < 0) {
6005     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6006   } else {
6007     PetscInt pStart, pEnd;
6008 
6009     if (start) *start = 0;
6010     if (end)   *end   = 0;
6011     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6012     if (pStart == pEnd) PetscFunctionReturn(0);
6013   }
6014   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6015   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6016   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6017   depth = label->stratumValues[label->numStrata-1] - stratumValue;
6018   if ((depth < 0) || (depth >= label->numStrata)) {
6019     if (start) *start = 0;
6020     if (end)   *end   = 0;
6021   } else {
6022     if (start) *start = label->points[label->stratumOffsets[depth]];
6023     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
6024   }
6025   PetscFunctionReturn(0);
6026 }
6027 
6028 #undef __FUNCT__
6029 #define __FUNCT__ "DMPlexCreateSectionInitial"
6030 /* Set the number of dof on each point and separate by fields */
6031 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6032 {
6033   PetscInt      *numDofTot;
6034   PetscInt       pStart = 0, pEnd = 0;
6035   PetscInt       p, d, f;
6036   PetscErrorCode ierr;
6037 
6038   PetscFunctionBegin;
6039   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6040   for (d = 0; d <= dim; ++d) {
6041     numDofTot[d] = 0;
6042     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6043   }
6044   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6045   if (numFields > 0) {
6046     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6047     if (numComp) {
6048       for (f = 0; f < numFields; ++f) {
6049         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6050       }
6051     }
6052   }
6053   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6054   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6055   for (d = 0; d <= dim; ++d) {
6056     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6057     for (p = pStart; p < pEnd; ++p) {
6058       for (f = 0; f < numFields; ++f) {
6059         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6060       }
6061       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6062     }
6063   }
6064   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6065   PetscFunctionReturn(0);
6066 }
6067 
6068 #undef __FUNCT__
6069 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6070 /* Set the number of dof on each point and separate by fields
6071    If constDof is PETSC_DETERMINE, constrain every dof on the point
6072 */
6073 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6074 {
6075   PetscInt       numFields;
6076   PetscInt       bc;
6077   PetscErrorCode ierr;
6078 
6079   PetscFunctionBegin;
6080   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6081   for (bc = 0; bc < numBC; ++bc) {
6082     PetscInt        field = 0;
6083     const PetscInt *idx;
6084     PetscInt        n, i;
6085 
6086     if (numFields) field = bcField[bc];
6087     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6088     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6089     for (i = 0; i < n; ++i) {
6090       const PetscInt p        = idx[i];
6091       PetscInt       numConst = constDof;
6092 
6093       /* Constrain every dof on the point */
6094       if (numConst < 0) {
6095         if (numFields) {
6096           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6097         } else {
6098           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6099         }
6100       }
6101       if (numFields) {
6102         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6103       }
6104       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6105     }
6106     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6107   }
6108   PetscFunctionReturn(0);
6109 }
6110 
6111 #undef __FUNCT__
6112 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6113 /* Set the constrained indices on each point and separate by fields */
6114 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6115 {
6116   PetscInt      *maxConstraints;
6117   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6118   PetscErrorCode ierr;
6119 
6120   PetscFunctionBegin;
6121   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6122   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6123   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6124   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6125   for (p = pStart; p < pEnd; ++p) {
6126     PetscInt cdof;
6127 
6128     if (numFields) {
6129       for (f = 0; f < numFields; ++f) {
6130         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6131         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6132       }
6133     } else {
6134       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6135       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6136     }
6137   }
6138   for (f = 0; f < numFields; ++f) {
6139     maxConstraints[numFields] += maxConstraints[f];
6140   }
6141   if (maxConstraints[numFields]) {
6142     PetscInt *indices;
6143 
6144     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6145     for (p = pStart; p < pEnd; ++p) {
6146       PetscInt cdof, d;
6147 
6148       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6149       if (cdof) {
6150         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6151         if (numFields) {
6152           PetscInt numConst = 0, foff = 0;
6153 
6154           for (f = 0; f < numFields; ++f) {
6155             PetscInt cfdof, fdof;
6156 
6157             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6158             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6159             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6160             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6161             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6162             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6163             numConst += cfdof;
6164             foff     += fdof;
6165           }
6166           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6167         } else {
6168           for (d = 0; d < cdof; ++d) indices[d] = d;
6169         }
6170         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6171       }
6172     }
6173     ierr = PetscFree(indices);CHKERRQ(ierr);
6174   }
6175   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6176   PetscFunctionReturn(0);
6177 }
6178 
6179 #undef __FUNCT__
6180 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6181 /* Set the constrained field indices on each point */
6182 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6183 {
6184   const PetscInt *points, *indices;
6185   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6186   PetscErrorCode  ierr;
6187 
6188   PetscFunctionBegin;
6189   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6190   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6191 
6192   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6193   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6194   if (!constraintIndices) {
6195     PetscInt *idx, i;
6196 
6197     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6198     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6199     for (i = 0; i < maxDof; ++i) idx[i] = i;
6200     for (p = 0; p < numPoints; ++p) {
6201       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6202     }
6203     ierr = PetscFree(idx);CHKERRQ(ierr);
6204   } else {
6205     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6206     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6207     for (p = 0; p < numPoints; ++p) {
6208       PetscInt fcdof;
6209 
6210       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6211       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);
6212       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6213     }
6214     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6215   }
6216   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6217   PetscFunctionReturn(0);
6218 }
6219 
6220 #undef __FUNCT__
6221 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6222 /* Set the constrained indices on each point and separate by fields */
6223 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6224 {
6225   PetscInt      *indices;
6226   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6227   PetscErrorCode ierr;
6228 
6229   PetscFunctionBegin;
6230   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6231   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6232   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6233   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6234   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6235   for (p = pStart; p < pEnd; ++p) {
6236     PetscInt cdof, d;
6237 
6238     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6239     if (cdof) {
6240       PetscInt numConst = 0, foff = 0;
6241 
6242       for (f = 0; f < numFields; ++f) {
6243         const PetscInt *fcind;
6244         PetscInt        fdof, fcdof;
6245 
6246         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6247         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6248         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6249         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6250         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6251         foff     += fdof;
6252         numConst += fcdof;
6253       }
6254       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6255       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6256     }
6257   }
6258   ierr = PetscFree(indices);CHKERRQ(ierr);
6259   PetscFunctionReturn(0);
6260 }
6261 
6262 #undef __FUNCT__
6263 #define __FUNCT__ "DMPlexCreateSection"
6264 /*@C
6265   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6266 
6267   Not Collective
6268 
6269   Input Parameters:
6270 + dm        - The DMPlex object
6271 . dim       - The spatial dimension of the problem
6272 . numFields - The number of fields in the problem
6273 . numComp   - An array of size numFields that holds the number of components for each field
6274 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6275 . numBC     - The number of boundary conditions
6276 . bcField   - An array of size numBC giving the field number for each boundry condition
6277 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6278 
6279   Output Parameter:
6280 . section - The PetscSection object
6281 
6282   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
6283   nubmer of dof for field 0 on each edge.
6284 
6285   Level: developer
6286 
6287   Fortran Notes:
6288   A Fortran 90 version is available as DMPlexCreateSectionF90()
6289 
6290 .keywords: mesh, elements
6291 .seealso: DMPlexCreate(), PetscSectionCreate()
6292 @*/
6293 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6294 {
6295   PetscErrorCode ierr;
6296 
6297   PetscFunctionBegin;
6298   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6299   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6300   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6301   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6302   {
6303     PetscBool view = PETSC_FALSE;
6304 
6305     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6306     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6307   }
6308   PetscFunctionReturn(0);
6309 }
6310 
6311 #undef __FUNCT__
6312 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6313 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6314 {
6315   PetscSection   section;
6316   PetscErrorCode ierr;
6317 
6318   PetscFunctionBegin;
6319   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6320   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6321   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6322   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6323   PetscFunctionReturn(0);
6324 }
6325 
6326 #undef __FUNCT__
6327 #define __FUNCT__ "DMPlexGetCoordinateSection"
6328 /*@
6329   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6330 
6331   Not Collective
6332 
6333   Input Parameter:
6334 . dm - The DMPlex object
6335 
6336   Output Parameter:
6337 . section - The PetscSection object
6338 
6339   Level: intermediate
6340 
6341 .keywords: mesh, coordinates
6342 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6343 @*/
6344 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6345 {
6346   DM             cdm;
6347   PetscErrorCode ierr;
6348 
6349   PetscFunctionBegin;
6350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6351   PetscValidPointer(section, 2);
6352   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6353   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6354   PetscFunctionReturn(0);
6355 }
6356 
6357 #undef __FUNCT__
6358 #define __FUNCT__ "DMPlexSetCoordinateSection"
6359 /*@
6360   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6361 
6362   Not Collective
6363 
6364   Input Parameters:
6365 + dm      - The DMPlex object
6366 - section - The PetscSection object
6367 
6368   Level: intermediate
6369 
6370 .keywords: mesh, coordinates
6371 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6372 @*/
6373 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6374 {
6375   DM             cdm;
6376   PetscErrorCode ierr;
6377 
6378   PetscFunctionBegin;
6379   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6380   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6381   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6382   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6383   PetscFunctionReturn(0);
6384 }
6385 
6386 #undef __FUNCT__
6387 #define __FUNCT__ "DMPlexGetConeSection"
6388 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6389 {
6390   DM_Plex *mesh = (DM_Plex*) dm->data;
6391 
6392   PetscFunctionBegin;
6393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6394   if (section) *section = mesh->coneSection;
6395   PetscFunctionReturn(0);
6396 }
6397 
6398 #undef __FUNCT__
6399 #define __FUNCT__ "DMPlexGetCones"
6400 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6401 {
6402   DM_Plex *mesh = (DM_Plex*) dm->data;
6403 
6404   PetscFunctionBegin;
6405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6406   if (cones) *cones = mesh->cones;
6407   PetscFunctionReturn(0);
6408 }
6409 
6410 #undef __FUNCT__
6411 #define __FUNCT__ "DMPlexGetConeOrientations"
6412 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6413 {
6414   DM_Plex *mesh = (DM_Plex*) dm->data;
6415 
6416   PetscFunctionBegin;
6417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6418   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6419   PetscFunctionReturn(0);
6420 }
6421 
6422 /******************************** FEM Support **********************************/
6423 
6424 #undef __FUNCT__
6425 #define __FUNCT__ "DMPlexVecGetClosure"
6426 /*@C
6427   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6428 
6429   Not collective
6430 
6431   Input Parameters:
6432 + dm - The DM
6433 . section - The section describing the layout in v, or NULL to use the default section
6434 . v - The local vector
6435 - point - The sieve point in the DM
6436 
6437   Output Parameters:
6438 + csize - The number of values in the closure, or NULL
6439 - values - The array of values, which is a borrowed array and should not be freed
6440 
6441   Fortran Notes:
6442   Since it returns an array, this routine is only available in Fortran 90, and you must
6443   include petsc.h90 in your code.
6444 
6445   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6446 
6447   Level: intermediate
6448 
6449 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6450 @*/
6451 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6452 {
6453   PetscScalar   *array, *vArray;
6454   PetscInt      *points = NULL;
6455   PetscInt       offsets[32];
6456   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6457   PetscErrorCode ierr;
6458 
6459   PetscFunctionBegin;
6460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6461   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6462   if (!section) {
6463     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6464   }
6465   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6466   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6467   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6468   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6469   /* Compress out points not in the section */
6470   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6471   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6472     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6473       points[q*2]   = points[p];
6474       points[q*2+1] = points[p+1];
6475       ++q;
6476     }
6477   }
6478   numPoints = q;
6479   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6480     PetscInt dof, fdof;
6481 
6482     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6483     for (f = 0; f < numFields; ++f) {
6484       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6485       offsets[f+1] += fdof;
6486     }
6487     size += dof;
6488   }
6489   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6490   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6491   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6492   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6493   for (p = 0; p < numPoints*2; p += 2) {
6494     PetscInt     o = points[p+1];
6495     PetscInt     dof, off, d;
6496     PetscScalar *varr;
6497 
6498     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6499     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6500     varr = &vArray[off];
6501     if (numFields) {
6502       PetscInt fdof, foff, fcomp, f, c;
6503 
6504       for (f = 0, foff = 0; f < numFields; ++f) {
6505         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6506         if (o >= 0) {
6507           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6508             array[offsets[f]] = varr[foff+d];
6509           }
6510         } else {
6511           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6512           for (d = fdof/fcomp-1; d >= 0; --d) {
6513             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6514               array[offsets[f]] = varr[foff+d*fcomp+c];
6515             }
6516           }
6517         }
6518         foff += fdof;
6519       }
6520     } else {
6521       if (o >= 0) {
6522         for (d = 0; d < dof; ++d, ++offsets[0]) {
6523           array[offsets[0]] = varr[d];
6524         }
6525       } else {
6526         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6527           array[offsets[0]] = varr[d];
6528         }
6529       }
6530     }
6531   }
6532   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6533   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6534   if (csize) *csize = size;
6535   *values = array;
6536   PetscFunctionReturn(0);
6537 }
6538 
6539 #undef __FUNCT__
6540 #define __FUNCT__ "DMPlexVecRestoreClosure"
6541 /*@C
6542   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6543 
6544   Not collective
6545 
6546   Input Parameters:
6547 + dm - The DM
6548 . section - The section describing the layout in v, or NULL to use the default section
6549 . v - The local vector
6550 . point - The sieve point in the DM
6551 . csize - The number of values in the closure, or NULL
6552 - values - The array of values, which is a borrowed array and should not be freed
6553 
6554   Fortran Notes:
6555   Since it returns an array, this routine is only available in Fortran 90, and you must
6556   include petsc.h90 in your code.
6557 
6558   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6559 
6560   Level: intermediate
6561 
6562 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6563 @*/
6564 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6565 {
6566   PetscInt       size = 0;
6567   PetscErrorCode ierr;
6568 
6569   PetscFunctionBegin;
6570   /* Should work without recalculating size */
6571   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6572   PetscFunctionReturn(0);
6573 }
6574 
6575 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6576 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6577 
6578 #undef __FUNCT__
6579 #define __FUNCT__ "updatePoint_private"
6580 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6581 {
6582   PetscInt        cdof;   /* The number of constraints on this point */
6583   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6584   PetscScalar    *a;
6585   PetscInt        off, cind = 0, k;
6586   PetscErrorCode  ierr;
6587 
6588   PetscFunctionBegin;
6589   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6590   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6591   a    = &array[off];
6592   if (!cdof || setBC) {
6593     if (orientation >= 0) {
6594       for (k = 0; k < dof; ++k) {
6595         fuse(&a[k], values[k]);
6596       }
6597     } else {
6598       for (k = 0; k < dof; ++k) {
6599         fuse(&a[k], values[dof-k-1]);
6600       }
6601     }
6602   } else {
6603     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6604     if (orientation >= 0) {
6605       for (k = 0; k < dof; ++k) {
6606         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6607         fuse(&a[k], values[k]);
6608       }
6609     } else {
6610       for (k = 0; k < dof; ++k) {
6611         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6612         fuse(&a[k], values[dof-k-1]);
6613       }
6614     }
6615   }
6616   PetscFunctionReturn(0);
6617 }
6618 
6619 #undef __FUNCT__
6620 #define __FUNCT__ "updatePointFields_private"
6621 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6622 {
6623   PetscScalar   *a;
6624   PetscInt       numFields, off, foff, f;
6625   PetscErrorCode ierr;
6626 
6627   PetscFunctionBegin;
6628   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6629   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6630   a    = &array[off];
6631   for (f = 0, foff = 0; f < numFields; ++f) {
6632     PetscInt        fdof, fcomp, fcdof;
6633     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6634     PetscInt        cind = 0, k, c;
6635 
6636     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6637     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6638     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6639     if (!fcdof || setBC) {
6640       if (orientation >= 0) {
6641         for (k = 0; k < fdof; ++k) {
6642           fuse(&a[foff+k], values[foffs[f]+k]);
6643         }
6644       } else {
6645         for (k = fdof/fcomp-1; k >= 0; --k) {
6646           for (c = 0; c < fcomp; ++c) {
6647             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6648           }
6649         }
6650       }
6651     } else {
6652       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6653       if (orientation >= 0) {
6654         for (k = 0; k < fdof; ++k) {
6655           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6656           fuse(&a[foff+k], values[foffs[f]+k]);
6657         }
6658       } else {
6659         for (k = fdof/fcomp-1; k >= 0; --k) {
6660           for (c = 0; c < fcomp; ++c) {
6661             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6662             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6663           }
6664         }
6665       }
6666     }
6667     foff     += fdof;
6668     foffs[f] += fdof;
6669   }
6670   PetscFunctionReturn(0);
6671 }
6672 
6673 #undef __FUNCT__
6674 #define __FUNCT__ "DMPlexVecSetClosure"
6675 /*@C
6676   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6677 
6678   Not collective
6679 
6680   Input Parameters:
6681 + dm - The DM
6682 . section - The section describing the layout in v, or NULL to use the default section
6683 . v - The local vector
6684 . point - The sieve point in the DM
6685 . values - The array of values
6686 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6687 
6688   Fortran Notes:
6689   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6690 
6691   Level: intermediate
6692 
6693 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6694 @*/
6695 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6696 {
6697   PetscScalar   *array;
6698   PetscInt      *points = NULL;
6699   PetscInt       offsets[32];
6700   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6701   PetscErrorCode ierr;
6702 
6703   PetscFunctionBegin;
6704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6705   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6706   if (!section) {
6707     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6708   }
6709   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6710   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6711   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6712   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6713   /* Compress out points not in the section */
6714   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6715   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6716     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6717       points[q*2]   = points[p];
6718       points[q*2+1] = points[p+1];
6719       ++q;
6720     }
6721   }
6722   numPoints = q;
6723   for (p = 0; p < numPoints*2; p += 2) {
6724     PetscInt fdof;
6725 
6726     for (f = 0; f < numFields; ++f) {
6727       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6728       offsets[f+1] += fdof;
6729     }
6730   }
6731   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6732   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6733   if (numFields) {
6734     switch (mode) {
6735     case INSERT_VALUES:
6736       for (p = 0; p < numPoints*2; p += 2) {
6737         PetscInt o = points[p+1];
6738         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6739       } break;
6740     case INSERT_ALL_VALUES:
6741       for (p = 0; p < numPoints*2; p += 2) {
6742         PetscInt o = points[p+1];
6743         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6744       } break;
6745     case ADD_VALUES:
6746       for (p = 0; p < numPoints*2; p += 2) {
6747         PetscInt o = points[p+1];
6748         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6749       } break;
6750     case ADD_ALL_VALUES:
6751       for (p = 0; p < numPoints*2; p += 2) {
6752         PetscInt o = points[p+1];
6753         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6754       } break;
6755     default:
6756       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6757     }
6758   } else {
6759     switch (mode) {
6760     case INSERT_VALUES:
6761       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6762         PetscInt o = points[p+1];
6763         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6764         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6765       } break;
6766     case INSERT_ALL_VALUES:
6767       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6768         PetscInt o = points[p+1];
6769         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6770         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6771       } break;
6772     case ADD_VALUES:
6773       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6774         PetscInt o = points[p+1];
6775         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6776         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6777       } break;
6778     case ADD_ALL_VALUES:
6779       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6780         PetscInt o = points[p+1];
6781         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6782         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6783       } break;
6784     default:
6785       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6786     }
6787   }
6788   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6789   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6790   PetscFunctionReturn(0);
6791 }
6792 
6793 #undef __FUNCT__
6794 #define __FUNCT__ "DMPlexPrintMatSetValues"
6795 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6796 {
6797   PetscMPIInt    rank;
6798   PetscInt       i, j;
6799   PetscErrorCode ierr;
6800 
6801   PetscFunctionBegin;
6802   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
6803   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
6804   for (i = 0; i < numIndices; i++) {
6805     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
6806   }
6807   for (i = 0; i < numIndices; i++) {
6808     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
6809     for (j = 0; j < numIndices; j++) {
6810 #if defined(PETSC_USE_COMPLEX)
6811       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
6812 #else
6813       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
6814 #endif
6815     }
6816     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6817   }
6818   PetscFunctionReturn(0);
6819 }
6820 
6821 #undef __FUNCT__
6822 #define __FUNCT__ "indicesPoint_private"
6823 /* . off - The global offset of this point */
6824 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6825 {
6826   PetscInt        dof;    /* The number of unknowns on this point */
6827   PetscInt        cdof;   /* The number of constraints on this point */
6828   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6829   PetscInt        cind = 0, k;
6830   PetscErrorCode  ierr;
6831 
6832   PetscFunctionBegin;
6833   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6834   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6835   if (!cdof || setBC) {
6836     if (orientation >= 0) {
6837       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6838     } else {
6839       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6840     }
6841   } else {
6842     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6843     if (orientation >= 0) {
6844       for (k = 0; k < dof; ++k) {
6845         if ((cind < cdof) && (k == cdofs[cind])) {
6846           /* Insert check for returning constrained indices */
6847           indices[*loff+k] = -(off+k+1);
6848           ++cind;
6849         } else {
6850           indices[*loff+k] = off+k-cind;
6851         }
6852       }
6853     } else {
6854       for (k = 0; k < dof; ++k) {
6855         if ((cind < cdof) && (k == cdofs[cind])) {
6856           /* Insert check for returning constrained indices */
6857           indices[*loff+dof-k-1] = -(off+k+1);
6858           ++cind;
6859         } else {
6860           indices[*loff+dof-k-1] = off+k-cind;
6861         }
6862       }
6863     }
6864   }
6865   *loff += dof;
6866   PetscFunctionReturn(0);
6867 }
6868 
6869 #undef __FUNCT__
6870 #define __FUNCT__ "indicesPointFields_private"
6871 /* . off - The global offset of this point */
6872 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
6873 {
6874   PetscInt       numFields, foff, f;
6875   PetscErrorCode ierr;
6876 
6877   PetscFunctionBegin;
6878   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6879   for (f = 0, foff = 0; f < numFields; ++f) {
6880     PetscInt        fdof, fcomp, cfdof;
6881     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6882     PetscInt        cind = 0, k, c;
6883 
6884     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6885     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6886     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6887     if (!cfdof || setBC) {
6888       if (orientation >= 0) {
6889         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6890       } else {
6891         for (k = fdof/fcomp-1; k >= 0; --k) {
6892           for (c = 0; c < fcomp; ++c) {
6893             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6894           }
6895         }
6896       }
6897     } else {
6898       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6899       if (orientation >= 0) {
6900         for (k = 0; k < fdof; ++k) {
6901           if ((cind < cfdof) && (k == fcdofs[cind])) {
6902             indices[foffs[f]+k] = -(off+foff+k+1);
6903             ++cind;
6904           } else {
6905             indices[foffs[f]+k] = off+foff+k-cind;
6906           }
6907         }
6908       } else {
6909         for (k = fdof/fcomp-1; k >= 0; --k) {
6910           for (c = 0; c < fcomp; ++c) {
6911             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6912               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6913               ++cind;
6914             } else {
6915               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6916             }
6917           }
6918         }
6919       }
6920     }
6921     foff     += fdof - cfdof;
6922     foffs[f] += fdof;
6923   }
6924   PetscFunctionReturn(0);
6925 }
6926 
6927 #undef __FUNCT__
6928 #define __FUNCT__ "DMPlexMatSetClosure"
6929 /*@C
6930   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
6931 
6932   Not collective
6933 
6934   Input Parameters:
6935 + dm - The DM
6936 . section - The section describing the layout in v, or NULL to use the default section
6937 . globalSection - The section describing the layout in v, or NULL to use the default section
6938 . A - The matrix
6939 . point - The sieve point in the DM
6940 . values - The array of values
6941 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6942 
6943   Fortran Notes:
6944   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6945 
6946   Level: intermediate
6947 
6948 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
6949 @*/
6950 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6951 {
6952   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6953   PetscInt      *points = NULL;
6954   PetscInt      *indices;
6955   PetscInt       offsets[32];
6956   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6957   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6958   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
6959   PetscErrorCode ierr;
6960 
6961   PetscFunctionBegin;
6962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6963   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
6964   if (useDefault) {
6965     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6966   }
6967   if (useGlobalDefault) {
6968     if (useDefault) {
6969       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
6970     } else {
6971       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6972     }
6973   }
6974   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6975   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6976   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6977   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6978   /* Compress out points not in the section */
6979   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6980   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6981     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6982       points[q*2]   = points[p];
6983       points[q*2+1] = points[p+1];
6984       ++q;
6985     }
6986   }
6987   numPoints = q;
6988   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6989     PetscInt fdof;
6990 
6991     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6992     for (f = 0; f < numFields; ++f) {
6993       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6994       offsets[f+1] += fdof;
6995     }
6996     numIndices += dof;
6997   }
6998   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6999 
7000   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
7001   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7002   if (numFields) {
7003     for (p = 0; p < numPoints*2; p += 2) {
7004       PetscInt o = points[p+1];
7005       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7006       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
7007     }
7008   } else {
7009     for (p = 0, off = 0; p < numPoints*2; p += 2) {
7010       PetscInt o = points[p+1];
7011       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7012       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
7013     }
7014   }
7015   if (useGlobalDefault && !useDefault) {
7016     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7017   }
7018   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7019   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7020   if (ierr) {
7021     PetscMPIInt    rank;
7022     PetscErrorCode ierr2;
7023 
7024     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7025     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7026     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7027     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7028     CHKERRQ(ierr);
7029   }
7030   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7031   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7032   PetscFunctionReturn(0);
7033 }
7034 
7035 #undef __FUNCT__
7036 #define __FUNCT__ "DMPlexGetHybridBounds"
7037 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7038 {
7039   DM_Plex       *mesh = (DM_Plex*) dm->data;
7040   PetscInt       dim;
7041   PetscErrorCode ierr;
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7045   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7046   if (cMax) *cMax = mesh->hybridPointMax[dim];
7047   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7048   if (eMax) *eMax = mesh->hybridPointMax[1];
7049   if (vMax) *vMax = mesh->hybridPointMax[0];
7050   PetscFunctionReturn(0);
7051 }
7052 
7053 #undef __FUNCT__
7054 #define __FUNCT__ "DMPlexSetHybridBounds"
7055 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7056 {
7057   DM_Plex       *mesh = (DM_Plex*) dm->data;
7058   PetscInt       dim;
7059   PetscErrorCode ierr;
7060 
7061   PetscFunctionBegin;
7062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7063   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7064   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7065   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7066   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7067   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7068   PetscFunctionReturn(0);
7069 }
7070 
7071 #undef __FUNCT__
7072 #define __FUNCT__ "DMPlexGetVTKCellHeight"
7073 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7074 {
7075   DM_Plex *mesh = (DM_Plex*) dm->data;
7076 
7077   PetscFunctionBegin;
7078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7079   PetscValidPointer(cellHeight, 2);
7080   *cellHeight = mesh->vtkCellHeight;
7081   PetscFunctionReturn(0);
7082 }
7083 
7084 #undef __FUNCT__
7085 #define __FUNCT__ "DMPlexSetVTKCellHeight"
7086 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7087 {
7088   DM_Plex *mesh = (DM_Plex*) dm->data;
7089 
7090   PetscFunctionBegin;
7091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7092   mesh->vtkCellHeight = cellHeight;
7093   PetscFunctionReturn(0);
7094 }
7095 
7096 #undef __FUNCT__
7097 #define __FUNCT__ "DMPlexCreateNumbering_Private"
7098 /* We can easily have a form that takes an IS instead */
7099 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7100 {
7101   PetscSection   section, globalSection;
7102   PetscInt      *numbers, p;
7103   PetscErrorCode ierr;
7104 
7105   PetscFunctionBegin;
7106   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7107   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7108   for (p = pStart; p < pEnd; ++p) {
7109     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7110   }
7111   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7112   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7113   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
7114   for (p = pStart; p < pEnd; ++p) {
7115     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7116   }
7117   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7118   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7119   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7120   PetscFunctionReturn(0);
7121 }
7122 
7123 #undef __FUNCT__
7124 #define __FUNCT__ "DMPlexGetCellNumbering"
7125 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7126 {
7127   DM_Plex       *mesh = (DM_Plex*) dm->data;
7128   PetscInt       cellHeight, cStart, cEnd, cMax;
7129   PetscErrorCode ierr;
7130 
7131   PetscFunctionBegin;
7132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7133   if (!mesh->globalCellNumbers) {
7134     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7135     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7136     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7137     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7138     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
7139   }
7140   *globalCellNumbers = mesh->globalCellNumbers;
7141   PetscFunctionReturn(0);
7142 }
7143 
7144 #undef __FUNCT__
7145 #define __FUNCT__ "DMPlexGetVertexNumbering"
7146 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7147 {
7148   DM_Plex       *mesh = (DM_Plex*) dm->data;
7149   PetscInt       vStart, vEnd, vMax;
7150   PetscErrorCode ierr;
7151 
7152   PetscFunctionBegin;
7153   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7154   if (!mesh->globalVertexNumbers) {
7155     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7156     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
7157     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
7158     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
7159   }
7160   *globalVertexNumbers = mesh->globalVertexNumbers;
7161   PetscFunctionReturn(0);
7162 }
7163 
7164 
7165 #undef __FUNCT__
7166 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
7167 /*@C
7168   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7169   the local section and an SF describing the section point overlap.
7170 
7171   Input Parameters:
7172   + s - The PetscSection for the local field layout
7173   . sf - The SF describing parallel layout of the section points
7174   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7175   . label - The label specifying the points
7176   - labelValue - The label stratum specifying the points
7177 
7178   Output Parameter:
7179   . gsection - The PetscSection for the global field layout
7180 
7181   Note: This gives negative sizes and offsets to points not owned by this process
7182 
7183   Level: developer
7184 
7185 .seealso: PetscSectionCreate()
7186 @*/
7187 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7188 {
7189   PetscInt      *neg;
7190   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
7191   PetscErrorCode ierr;
7192 
7193   PetscFunctionBegin;
7194   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
7195   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
7196   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7197   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7198   /* Mark ghost points with negative dof */
7199   for (p = pStart; p < pEnd; ++p) {
7200     PetscInt value;
7201 
7202     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7203     if (value != labelValue) continue;
7204     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7205     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7206     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7207     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7208     neg[p-pStart] = -(dof+1);
7209   }
7210   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7211   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7212   if (nroots >= 0) {
7213     if (nroots > pEnd - pStart) {
7214       PetscInt *tmpDof;
7215       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7216       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
7217       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7218       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7219       for (p = pStart; p < pEnd; ++p) {
7220         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7221       }
7222       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
7223     } else {
7224       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7225       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7226     }
7227   }
7228   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7229   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7230     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7231 
7232     (*gsection)->atlasOff[p] = off;
7233 
7234     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7235   }
7236   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7237   globalOff -= off;
7238   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7239     (*gsection)->atlasOff[p] += globalOff;
7240 
7241     neg[p] = -((*gsection)->atlasOff[p]+1);
7242   }
7243   /* Put in negative offsets for ghost points */
7244   if (nroots >= 0) {
7245     if (nroots > pEnd - pStart) {
7246       PetscInt *tmpOff;
7247       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7248       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7249       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7250       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7251       for (p = pStart; p < pEnd; ++p) {
7252         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7253       }
7254       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
7255     } else {
7256       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7257       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7258     }
7259   }
7260   ierr = PetscFree(neg);CHKERRQ(ierr);
7261   PetscFunctionReturn(0);
7262 }
7263