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