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