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