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