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