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