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