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