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