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