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