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