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