xref: /petsc/src/dm/impls/plex/plex.c (revision 471ecdac3773a6638aec45dd793f678e9beedcdc)
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, *packPoints;
2488   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2489   PetscErrorCode  ierr;
2490   PetscBT         bt;
2491   PetscSegBuffer  segpack,segpart;
2492 
2493   PetscFunctionBegin;
2494   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2495   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2496   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2497   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2498   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2499   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2500   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2501   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2502   for (rank = rStart; rank < rEnd; ++rank) {
2503     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2504 
2505     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2506     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2507     for (p = 0; p < numPoints; ++p) {
2508       PetscInt  point   = partArray[offset+p], closureSize, c;
2509       PetscInt *closure = NULL;
2510 
2511       /* TODO Include support for height > 0 case */
2512       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2513       for (c=0; c<closureSize; c++) {
2514         PetscInt cpoint = closure[c*2];
2515         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2516           PetscInt *PETSC_RESTRICT pt;
2517           partSize++;
2518           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2519           *pt = cpoint;
2520         }
2521       }
2522       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2523     }
2524     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2525     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2526     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2527     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2528     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2529   }
2530   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2531   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2532 
2533   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2534   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2535   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2536 
2537   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2538   for (rank = rStart; rank < rEnd; ++rank) {
2539     PetscInt numPoints, offset;
2540 
2541     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2542     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2543     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2544     packPoints += numPoints;
2545   }
2546 
2547   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2548   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2549   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexDistributeField"
2555 /*
2556   Input Parameters:
2557 . originalSection
2558 , originalVec
2559 
2560   Output Parameters:
2561 . newSection
2562 . newVec
2563 */
2564 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2565 {
2566   PetscSF        fieldSF;
2567   PetscInt      *remoteOffsets, fieldSize;
2568   PetscScalar   *originalValues, *newValues;
2569   PetscErrorCode ierr;
2570 
2571   PetscFunctionBegin;
2572   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2573 
2574   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2575   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2576   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2577 
2578   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2579   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2580   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2581   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2582   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2583   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2584   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2585   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2586   PetscFunctionReturn(0);
2587 }
2588 
2589 #undef __FUNCT__
2590 #define __FUNCT__ "DMPlexDistribute"
2591 /*@C
2592   DMPlexDistribute - Distributes the mesh and any associated sections.
2593 
2594   Not Collective
2595 
2596   Input Parameter:
2597 + dm  - The original DMPlex object
2598 . partitioner - The partitioning package, or NULL for the default
2599 - overlap - The overlap of partitions, 0 is the default
2600 
2601   Output Parameter:
2602 . parallelMesh - The distributed DMPlex object, or NULL
2603 
2604   Note: If the mesh was not distributed, the return value is NULL
2605 
2606   Level: intermediate
2607 
2608 .keywords: mesh, elements
2609 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2610 @*/
2611 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2612 {
2613   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2614   MPI_Comm               comm;
2615   const PetscInt         height = 0;
2616   PetscInt               dim, numRemoteRanks;
2617   IS                     origCellPart,        cellPart,        part;
2618   PetscSection           origCellPartSection, cellPartSection, partSection;
2619   PetscSFNode           *remoteRanks;
2620   PetscSF                partSF, pointSF, coneSF;
2621   ISLocalToGlobalMapping renumbering;
2622   PetscSection           originalConeSection, newConeSection;
2623   PetscInt              *remoteOffsets;
2624   PetscInt              *cones, *newCones, newConesSize;
2625   PetscBool              flg;
2626   PetscMPIInt            rank, numProcs, p;
2627   PetscErrorCode         ierr;
2628 
2629   PetscFunctionBegin;
2630   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2631   PetscValidPointer(dmParallel,4);
2632 
2633   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2634   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2635   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2636   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2637 
2638   *dmParallel = NULL;
2639   if (numProcs == 1) PetscFunctionReturn(0);
2640 
2641   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2642   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2643   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2644   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2645   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2646   if (!rank) numRemoteRanks = numProcs;
2647   else       numRemoteRanks = 0;
2648   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2649   for (p = 0; p < numRemoteRanks; ++p) {
2650     remoteRanks[p].rank  = p;
2651     remoteRanks[p].index = 0;
2652   }
2653   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2654   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2655   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2656   if (flg) {
2657     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2658     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2659     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2660     if (origCellPart) {
2661       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2662       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2663       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2664     }
2665     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2666   }
2667   /* Close the partition over the mesh */
2668   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2669   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2670   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2671   /* Create new mesh */
2672   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2673   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2674   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2675   pmesh = (DM_Plex*) (*dmParallel)->data;
2676   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2677   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2678   if (flg) {
2679     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2680     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2681     ierr = ISView(part, NULL);CHKERRQ(ierr);
2682     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2683     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2684     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2685   }
2686   /* Distribute cone section */
2687   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2688   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2689   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2690   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2691   {
2692     PetscInt pStart, pEnd, p;
2693 
2694     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2695     for (p = pStart; p < pEnd; ++p) {
2696       PetscInt coneSize;
2697       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2698       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2699     }
2700   }
2701   /* Communicate and renumber cones */
2702   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2703   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2704   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2705   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2706   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2707   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2708   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2709   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2710   if (flg) {
2711     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2712     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2713     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2714     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2715     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2716   }
2717   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2718   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2719   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2720   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2721   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2722   /* Create supports and stratify sieve */
2723   {
2724     PetscInt pStart, pEnd;
2725 
2726     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2727     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2728   }
2729   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2730   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2731   /* Distribute Coordinates */
2732   {
2733     PetscSection originalCoordSection, newCoordSection;
2734     Vec          originalCoordinates, newCoordinates;
2735     const char  *name;
2736 
2737     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2738     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2739     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2740     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2741     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2742     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2743 
2744     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2745     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2746     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2747   }
2748   /* Distribute labels */
2749   {
2750     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2751     PetscInt numLabels = 0, l;
2752 
2753     /* Bcast number of labels */
2754     while (next) {
2755       ++numLabels; next = next->next;
2756     }
2757     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2758     next = mesh->labels;
2759     for (l = 0; l < numLabels; ++l) {
2760       DMLabel         newLabel;
2761       const PetscInt *partArray;
2762       char           *name;
2763       PetscInt       *stratumSizes = NULL, *points = NULL;
2764       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2765       PetscInt        nameSize, s, p;
2766       PetscBool       isdepth;
2767       size_t          len = 0;
2768 
2769       /* Bcast name (could filter for no points) */
2770       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2771       nameSize = len;
2772       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2773       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2774       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2775       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2776       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2777       if (isdepth) {            /* skip because "depth" is not distributed */
2778         ierr = PetscFree(name);CHKERRQ(ierr);
2779         if (!rank) next = next->next;
2780         continue;
2781       }
2782       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2783       newLabel->name = name;
2784       /* Bcast numStrata (could filter for no points in stratum) */
2785       if (!rank) newLabel->numStrata = next->numStrata;
2786       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2787       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2788                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2789                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2790       /* Bcast stratumValues (could filter for no points in stratum) */
2791       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2792       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2793       /* Find size on each process and Scatter */
2794       if (!rank) {
2795         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2796         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2797         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2798         for (s = 0; s < next->numStrata; ++s) {
2799           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2800             const PetscInt point = next->points[p];
2801             PetscInt       proc;
2802 
2803             for (proc = 0; proc < numProcs; ++proc) {
2804               PetscInt dof, off, pPart;
2805 
2806               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2807               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2808               for (pPart = off; pPart < off+dof; ++pPart) {
2809                 if (partArray[pPart] == point) {
2810                   ++stratumSizes[proc*next->numStrata+s];
2811                   break;
2812                 }
2813               }
2814             }
2815           }
2816         }
2817         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2818       }
2819       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2820       /* Calculate stratumOffsets */
2821       newLabel->stratumOffsets[0] = 0;
2822       for (s = 0; s < newLabel->numStrata; ++s) {
2823         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2824       }
2825       /* Pack points and Scatter */
2826       if (!rank) {
2827         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2828         displs[0] = 0;
2829         for (p = 0; p < numProcs; ++p) {
2830           sendcnts[p] = 0;
2831           for (s = 0; s < next->numStrata; ++s) {
2832             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2833           }
2834           offsets[p]  = displs[p];
2835           displs[p+1] = displs[p] + sendcnts[p];
2836         }
2837         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
2838         for (s = 0; s < next->numStrata; ++s) {
2839           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2840             const PetscInt point = next->points[p];
2841             PetscInt       proc;
2842 
2843             for (proc = 0; proc < numProcs; ++proc) {
2844               PetscInt dof, off, pPart;
2845 
2846               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2847               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2848               for (pPart = off; pPart < off+dof; ++pPart) {
2849                 if (partArray[pPart] == point) {
2850                   points[offsets[proc]++] = point;
2851                   break;
2852                 }
2853               }
2854             }
2855           }
2856         }
2857       }
2858       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
2859       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
2860       ierr = PetscFree(points);CHKERRQ(ierr);
2861       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
2862       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
2863       /* Renumber points */
2864       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
2865       /* Sort points */
2866       for (s = 0; s < newLabel->numStrata; ++s) {
2867         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
2868       }
2869       /* Insert into list */
2870       if (newNext) newNext->next = newLabel;
2871       else pmesh->labels = newLabel;
2872       newNext = newLabel;
2873       if (!rank) next = next->next;
2874     }
2875   }
2876   /* Cleanup Partition */
2877   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
2878   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
2879   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
2880   ierr = ISDestroy(&part);CHKERRQ(ierr);
2881   /* Create point SF for parallel mesh */
2882   {
2883     const PetscInt *leaves;
2884     PetscSFNode    *remotePoints, *rowners, *lowners;
2885     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
2886     PetscInt        pStart, pEnd;
2887 
2888     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
2889     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
2890     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
2891     for (p=0; p<numRoots; p++) {
2892       rowners[p].rank  = -1;
2893       rowners[p].index = -1;
2894     }
2895     if (origCellPart) {
2896       /* Make sure cells in the original partition are not assigned to other procs */
2897       const PetscInt *origCells;
2898 
2899       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
2900       for (p = 0; p < numProcs; ++p) {
2901         PetscInt dof, off, d;
2902 
2903         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
2904         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
2905         for (d = off; d < off+dof; ++d) {
2906           rowners[origCells[d]].rank = p;
2907         }
2908       }
2909       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
2910     }
2911     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
2912     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
2913 
2914     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2915     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2916     for (p = 0; p < numLeaves; ++p) {
2917       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
2918         lowners[p].rank  = rank;
2919         lowners[p].index = leaves ? leaves[p] : p;
2920       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
2921         lowners[p].rank  = -2;
2922         lowners[p].index = -2;
2923       }
2924     }
2925     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
2926       rowners[p].rank  = -3;
2927       rowners[p].index = -3;
2928     }
2929     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2930     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2931     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2932     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2933     for (p = 0; p < numLeaves; ++p) {
2934       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
2935       if (lowners[p].rank != rank) ++numGhostPoints;
2936     }
2937     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
2938     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
2939     for (p = 0, gp = 0; p < numLeaves; ++p) {
2940       if (lowners[p].rank != rank) {
2941         ghostPoints[gp]        = leaves ? leaves[p] : p;
2942         remotePoints[gp].rank  = lowners[p].rank;
2943         remotePoints[gp].index = lowners[p].index;
2944         ++gp;
2945       }
2946     }
2947     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
2948     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
2949     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
2950   }
2951   /* Cleanup */
2952   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
2953   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
2954   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2955   PetscFunctionReturn(0);
2956 }
2957 
2958 #if defined(PETSC_HAVE_TRIANGLE)
2959 #include <triangle.h>
2960 
2961 #undef __FUNCT__
2962 #define __FUNCT__ "InitInput_Triangle"
2963 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
2964 {
2965   PetscFunctionBegin;
2966   inputCtx->numberofpoints             = 0;
2967   inputCtx->numberofpointattributes    = 0;
2968   inputCtx->pointlist                  = NULL;
2969   inputCtx->pointattributelist         = NULL;
2970   inputCtx->pointmarkerlist            = NULL;
2971   inputCtx->numberofsegments           = 0;
2972   inputCtx->segmentlist                = NULL;
2973   inputCtx->segmentmarkerlist          = NULL;
2974   inputCtx->numberoftriangleattributes = 0;
2975   inputCtx->trianglelist               = NULL;
2976   inputCtx->numberofholes              = 0;
2977   inputCtx->holelist                   = NULL;
2978   inputCtx->numberofregions            = 0;
2979   inputCtx->regionlist                 = NULL;
2980   PetscFunctionReturn(0);
2981 }
2982 
2983 #undef __FUNCT__
2984 #define __FUNCT__ "InitOutput_Triangle"
2985 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
2986 {
2987   PetscFunctionBegin;
2988   outputCtx->numberofpoints        = 0;
2989   outputCtx->pointlist             = NULL;
2990   outputCtx->pointattributelist    = NULL;
2991   outputCtx->pointmarkerlist       = NULL;
2992   outputCtx->numberoftriangles     = 0;
2993   outputCtx->trianglelist          = NULL;
2994   outputCtx->triangleattributelist = NULL;
2995   outputCtx->neighborlist          = NULL;
2996   outputCtx->segmentlist           = NULL;
2997   outputCtx->segmentmarkerlist     = NULL;
2998   outputCtx->numberofedges         = 0;
2999   outputCtx->edgelist              = NULL;
3000   outputCtx->edgemarkerlist        = NULL;
3001   PetscFunctionReturn(0);
3002 }
3003 
3004 #undef __FUNCT__
3005 #define __FUNCT__ "FiniOutput_Triangle"
3006 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3007 {
3008   PetscFunctionBegin;
3009   free(outputCtx->pointmarkerlist);
3010   free(outputCtx->edgelist);
3011   free(outputCtx->edgemarkerlist);
3012   free(outputCtx->trianglelist);
3013   free(outputCtx->neighborlist);
3014   PetscFunctionReturn(0);
3015 }
3016 
3017 #undef __FUNCT__
3018 #define __FUNCT__ "DMPlexGenerate_Triangle"
3019 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3020 {
3021   MPI_Comm             comm;
3022   PetscInt             dim              = 2;
3023   const PetscBool      createConvexHull = PETSC_FALSE;
3024   const PetscBool      constrained      = PETSC_FALSE;
3025   struct triangulateio in;
3026   struct triangulateio out;
3027   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3028   PetscMPIInt          rank;
3029   PetscErrorCode       ierr;
3030 
3031   PetscFunctionBegin;
3032   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3033   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3034   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3035   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3036   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3037 
3038   in.numberofpoints = vEnd - vStart;
3039   if (in.numberofpoints > 0) {
3040     PetscSection coordSection;
3041     Vec          coordinates;
3042     PetscScalar *array;
3043 
3044     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3045     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3046     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3047     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3048     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3049     for (v = vStart; v < vEnd; ++v) {
3050       const PetscInt idx = v - vStart;
3051       PetscInt       off, d;
3052 
3053       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3054       for (d = 0; d < dim; ++d) {
3055         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3056       }
3057       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3058     }
3059     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3060   }
3061   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3062   in.numberofsegments = eEnd - eStart;
3063   if (in.numberofsegments > 0) {
3064     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3065     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3066     for (e = eStart; e < eEnd; ++e) {
3067       const PetscInt  idx = e - eStart;
3068       const PetscInt *cone;
3069 
3070       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3071 
3072       in.segmentlist[idx*2+0] = cone[0] - vStart;
3073       in.segmentlist[idx*2+1] = cone[1] - vStart;
3074 
3075       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3076     }
3077   }
3078 #if 0 /* Do not currently support holes */
3079   PetscReal *holeCoords;
3080   PetscInt   h, d;
3081 
3082   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3083   if (in.numberofholes > 0) {
3084     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3085     for (h = 0; h < in.numberofholes; ++h) {
3086       for (d = 0; d < dim; ++d) {
3087         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3088       }
3089     }
3090   }
3091 #endif
3092   if (!rank) {
3093     char args[32];
3094 
3095     /* Take away 'Q' for verbose output */
3096     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3097     if (createConvexHull) {
3098       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3099     }
3100     if (constrained) {
3101       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3102     }
3103     triangulate(args, &in, &out, NULL);
3104   }
3105   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3106   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3107   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3108   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3109   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3110 
3111   {
3112     const PetscInt numCorners  = 3;
3113     const PetscInt numCells    = out.numberoftriangles;
3114     const PetscInt numVertices = out.numberofpoints;
3115     const int     *cells      = out.trianglelist;
3116     const double  *meshCoords = out.pointlist;
3117 
3118     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3119     /* Set labels */
3120     for (v = 0; v < numVertices; ++v) {
3121       if (out.pointmarkerlist[v]) {
3122         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3123       }
3124     }
3125     if (interpolate) {
3126       for (e = 0; e < out.numberofedges; e++) {
3127         if (out.edgemarkerlist[e]) {
3128           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3129           const PetscInt *edges;
3130           PetscInt        numEdges;
3131 
3132           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3133           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3134           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3135           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3136         }
3137       }
3138     }
3139     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3140   }
3141 #if 0 /* Do not currently support holes */
3142   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3143 #endif
3144   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3145   PetscFunctionReturn(0);
3146 }
3147 
3148 #undef __FUNCT__
3149 #define __FUNCT__ "DMPlexRefine_Triangle"
3150 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3151 {
3152   MPI_Comm             comm;
3153   PetscInt             dim  = 2;
3154   struct triangulateio in;
3155   struct triangulateio out;
3156   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3157   PetscMPIInt          rank;
3158   PetscErrorCode       ierr;
3159 
3160   PetscFunctionBegin;
3161   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3162   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3163   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3164   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3165   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3166   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3167   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3168 
3169   in.numberofpoints = vEnd - vStart;
3170   if (in.numberofpoints > 0) {
3171     PetscSection coordSection;
3172     Vec          coordinates;
3173     PetscScalar *array;
3174 
3175     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3176     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3177     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3178     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3179     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3180     for (v = vStart; v < vEnd; ++v) {
3181       const PetscInt idx = v - vStart;
3182       PetscInt       off, d;
3183 
3184       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3185       for (d = 0; d < dim; ++d) {
3186         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3187       }
3188       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3189     }
3190     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3191   }
3192   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3193 
3194   in.numberofcorners   = 3;
3195   in.numberoftriangles = cEnd - cStart;
3196 
3197   in.trianglearealist  = (double*) maxVolumes;
3198   if (in.numberoftriangles > 0) {
3199     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3200     for (c = cStart; c < cEnd; ++c) {
3201       const PetscInt idx      = c - cStart;
3202       PetscInt      *closure = NULL;
3203       PetscInt       closureSize;
3204 
3205       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3206       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3207       for (v = 0; v < 3; ++v) {
3208         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3209       }
3210       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3211     }
3212   }
3213   /* TODO: Segment markers are missing on input */
3214 #if 0 /* Do not currently support holes */
3215   PetscReal *holeCoords;
3216   PetscInt   h, d;
3217 
3218   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3219   if (in.numberofholes > 0) {
3220     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3221     for (h = 0; h < in.numberofholes; ++h) {
3222       for (d = 0; d < dim; ++d) {
3223         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3224       }
3225     }
3226   }
3227 #endif
3228   if (!rank) {
3229     char args[32];
3230 
3231     /* Take away 'Q' for verbose output */
3232     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3233     triangulate(args, &in, &out, NULL);
3234   }
3235   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3236   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3237   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3238   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3239   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3240 
3241   {
3242     const PetscInt numCorners  = 3;
3243     const PetscInt numCells    = out.numberoftriangles;
3244     const PetscInt numVertices = out.numberofpoints;
3245     const int     *cells      = out.trianglelist;
3246     const double  *meshCoords = out.pointlist;
3247     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3248 
3249     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3250     /* Set labels */
3251     for (v = 0; v < numVertices; ++v) {
3252       if (out.pointmarkerlist[v]) {
3253         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3254       }
3255     }
3256     if (interpolate) {
3257       PetscInt e;
3258 
3259       for (e = 0; e < out.numberofedges; e++) {
3260         if (out.edgemarkerlist[e]) {
3261           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3262           const PetscInt *edges;
3263           PetscInt        numEdges;
3264 
3265           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3266           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3267           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3268           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3269         }
3270       }
3271     }
3272     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3273   }
3274 #if 0 /* Do not currently support holes */
3275   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3276 #endif
3277   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3278   PetscFunctionReturn(0);
3279 }
3280 #endif
3281 
3282 #if defined(PETSC_HAVE_TETGEN)
3283 #include <tetgen.h>
3284 #undef __FUNCT__
3285 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3286 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3287 {
3288   MPI_Comm       comm;
3289   const PetscInt dim  = 3;
3290   ::tetgenio     in;
3291   ::tetgenio     out;
3292   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3293   PetscMPIInt    rank;
3294   PetscErrorCode ierr;
3295 
3296   PetscFunctionBegin;
3297   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3298   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3299   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3300   in.numberofpoints = vEnd - vStart;
3301   if (in.numberofpoints > 0) {
3302     PetscSection coordSection;
3303     Vec          coordinates;
3304     PetscScalar *array;
3305 
3306     in.pointlist       = new double[in.numberofpoints*dim];
3307     in.pointmarkerlist = new int[in.numberofpoints];
3308 
3309     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3310     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3311     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3312     for (v = vStart; v < vEnd; ++v) {
3313       const PetscInt idx = v - vStart;
3314       PetscInt       off, d;
3315 
3316       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3317       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3318       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3319     }
3320     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3321   }
3322   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3323 
3324   in.numberoffacets = fEnd - fStart;
3325   if (in.numberoffacets > 0) {
3326     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3327     in.facetmarkerlist = new int[in.numberoffacets];
3328     for (f = fStart; f < fEnd; ++f) {
3329       const PetscInt idx     = f - fStart;
3330       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3331 
3332       in.facetlist[idx].numberofpolygons = 1;
3333       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3334       in.facetlist[idx].numberofholes    = 0;
3335       in.facetlist[idx].holelist         = NULL;
3336 
3337       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3338       for (p = 0; p < numPoints*2; p += 2) {
3339         const PetscInt point = points[p];
3340         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3341       }
3342 
3343       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3344       poly->numberofvertices = numVertices;
3345       poly->vertexlist       = new int[poly->numberofvertices];
3346       for (v = 0; v < numVertices; ++v) {
3347         const PetscInt vIdx = points[v] - vStart;
3348         poly->vertexlist[v] = vIdx;
3349       }
3350       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3351       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3352     }
3353   }
3354   if (!rank) {
3355     char args[32];
3356 
3357     /* Take away 'Q' for verbose output */
3358     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3359     ::tetrahedralize(args, &in, &out);
3360   }
3361   {
3362     const PetscInt numCorners  = 4;
3363     const PetscInt numCells    = out.numberoftetrahedra;
3364     const PetscInt numVertices = out.numberofpoints;
3365     const int     *cells      = out.tetrahedronlist;
3366     const double  *meshCoords = out.pointlist;
3367 
3368     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3369     /* Set labels */
3370     for (v = 0; v < numVertices; ++v) {
3371       if (out.pointmarkerlist[v]) {
3372         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3373       }
3374     }
3375     if (interpolate) {
3376       PetscInt e;
3377 
3378       for (e = 0; e < out.numberofedges; e++) {
3379         if (out.edgemarkerlist[e]) {
3380           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3381           const PetscInt *edges;
3382           PetscInt        numEdges;
3383 
3384           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3385           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3386           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3387           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3388         }
3389       }
3390       for (f = 0; f < out.numberoftrifaces; f++) {
3391         if (out.trifacemarkerlist[f]) {
3392           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3393           const PetscInt *faces;
3394           PetscInt        numFaces;
3395 
3396           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3397           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3398           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3399           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3400         }
3401       }
3402     }
3403     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3404   }
3405   PetscFunctionReturn(0);
3406 }
3407 
3408 #undef __FUNCT__
3409 #define __FUNCT__ "DMPlexRefine_Tetgen"
3410 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3411 {
3412   MPI_Comm       comm;
3413   const PetscInt dim  = 3;
3414   ::tetgenio     in;
3415   ::tetgenio     out;
3416   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3417   PetscMPIInt    rank;
3418   PetscErrorCode ierr;
3419 
3420   PetscFunctionBegin;
3421   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3422   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3423   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3424   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3425   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3426 
3427   in.numberofpoints = vEnd - vStart;
3428   if (in.numberofpoints > 0) {
3429     PetscSection coordSection;
3430     Vec          coordinates;
3431     PetscScalar *array;
3432 
3433     in.pointlist       = new double[in.numberofpoints*dim];
3434     in.pointmarkerlist = new int[in.numberofpoints];
3435 
3436     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3437     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3438     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3439     for (v = vStart; v < vEnd; ++v) {
3440       const PetscInt idx = v - vStart;
3441       PetscInt       off, d;
3442 
3443       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3444       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3445       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3446     }
3447     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3448   }
3449   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3450 
3451   in.numberofcorners       = 4;
3452   in.numberoftetrahedra    = cEnd - cStart;
3453   in.tetrahedronvolumelist = (double*) maxVolumes;
3454   if (in.numberoftetrahedra > 0) {
3455     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3456     for (c = cStart; c < cEnd; ++c) {
3457       const PetscInt idx      = c - cStart;
3458       PetscInt      *closure = NULL;
3459       PetscInt       closureSize;
3460 
3461       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3462       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3463       for (v = 0; v < 4; ++v) {
3464         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3465       }
3466       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3467     }
3468   }
3469   /* TODO: Put in boundary faces with markers */
3470   if (!rank) {
3471     char args[32];
3472 
3473     /* Take away 'Q' for verbose output */
3474     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3475     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3476     ::tetrahedralize(args, &in, &out);
3477   }
3478   in.tetrahedronvolumelist = NULL;
3479 
3480   {
3481     const PetscInt numCorners  = 4;
3482     const PetscInt numCells    = out.numberoftetrahedra;
3483     const PetscInt numVertices = out.numberofpoints;
3484     const int     *cells      = out.tetrahedronlist;
3485     const double  *meshCoords = out.pointlist;
3486     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3487 
3488     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3489     /* Set labels */
3490     for (v = 0; v < numVertices; ++v) {
3491       if (out.pointmarkerlist[v]) {
3492         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3493       }
3494     }
3495     if (interpolate) {
3496       PetscInt e, f;
3497 
3498       for (e = 0; e < out.numberofedges; e++) {
3499         if (out.edgemarkerlist[e]) {
3500           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3501           const PetscInt *edges;
3502           PetscInt        numEdges;
3503 
3504           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3505           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3506           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3507           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3508         }
3509       }
3510       for (f = 0; f < out.numberoftrifaces; f++) {
3511         if (out.trifacemarkerlist[f]) {
3512           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3513           const PetscInt *faces;
3514           PetscInt        numFaces;
3515 
3516           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3517           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3518           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3519           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3520         }
3521       }
3522     }
3523     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3524   }
3525   PetscFunctionReturn(0);
3526 }
3527 #endif
3528 
3529 #if defined(PETSC_HAVE_CTETGEN)
3530 #include "ctetgen.h"
3531 
3532 #undef __FUNCT__
3533 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3534 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3535 {
3536   MPI_Comm       comm;
3537   const PetscInt dim  = 3;
3538   PLC           *in, *out;
3539   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3540   PetscMPIInt    rank;
3541   PetscErrorCode ierr;
3542 
3543   PetscFunctionBegin;
3544   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3545   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3546   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3547   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3548   ierr = PLCCreate(&in);CHKERRQ(ierr);
3549   ierr = PLCCreate(&out);CHKERRQ(ierr);
3550 
3551   in->numberofpoints = vEnd - vStart;
3552   if (in->numberofpoints > 0) {
3553     PetscSection coordSection;
3554     Vec          coordinates;
3555     PetscScalar *array;
3556 
3557     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3558     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3559     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3560     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3561     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3562     for (v = vStart; v < vEnd; ++v) {
3563       const PetscInt idx = v - vStart;
3564       PetscInt       off, d, m;
3565 
3566       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3567       for (d = 0; d < dim; ++d) {
3568         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3569       }
3570       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3571 
3572       in->pointmarkerlist[idx] = (int) m;
3573     }
3574     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3575   }
3576   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3577 
3578   in->numberoffacets = fEnd - fStart;
3579   if (in->numberoffacets > 0) {
3580     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3581     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3582     for (f = fStart; f < fEnd; ++f) {
3583       const PetscInt idx     = f - fStart;
3584       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3585       polygon       *poly;
3586 
3587       in->facetlist[idx].numberofpolygons = 1;
3588 
3589       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3590 
3591       in->facetlist[idx].numberofholes    = 0;
3592       in->facetlist[idx].holelist         = NULL;
3593 
3594       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3595       for (p = 0; p < numPoints*2; p += 2) {
3596         const PetscInt point = points[p];
3597         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3598       }
3599 
3600       poly                   = in->facetlist[idx].polygonlist;
3601       poly->numberofvertices = numVertices;
3602       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3603       for (v = 0; v < numVertices; ++v) {
3604         const PetscInt vIdx = points[v] - vStart;
3605         poly->vertexlist[v] = vIdx;
3606       }
3607       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3608       in->facetmarkerlist[idx] = (int) m;
3609       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3610     }
3611   }
3612   if (!rank) {
3613     TetGenOpts t;
3614 
3615     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3616     t.in        = boundary; /* Should go away */
3617     t.plc       = 1;
3618     t.quality   = 1;
3619     t.edgesout  = 1;
3620     t.zeroindex = 1;
3621     t.quiet     = 1;
3622     t.verbose   = verbose;
3623     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3624     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3625   }
3626   {
3627     const PetscInt numCorners  = 4;
3628     const PetscInt numCells    = out->numberoftetrahedra;
3629     const PetscInt numVertices = out->numberofpoints;
3630     const int     *cells      = out->tetrahedronlist;
3631     const double  *meshCoords = out->pointlist;
3632 
3633     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3634     /* Set labels */
3635     for (v = 0; v < numVertices; ++v) {
3636       if (out->pointmarkerlist[v]) {
3637         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3638       }
3639     }
3640     if (interpolate) {
3641       PetscInt e;
3642 
3643       for (e = 0; e < out->numberofedges; e++) {
3644         if (out->edgemarkerlist[e]) {
3645           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3646           const PetscInt *edges;
3647           PetscInt        numEdges;
3648 
3649           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3650           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3651           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3652           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3653         }
3654       }
3655       for (f = 0; f < out->numberoftrifaces; f++) {
3656         if (out->trifacemarkerlist[f]) {
3657           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3658           const PetscInt *faces;
3659           PetscInt        numFaces;
3660 
3661           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3662           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3663           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3664           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3665         }
3666       }
3667     }
3668     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3669   }
3670 
3671   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3672   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3673   PetscFunctionReturn(0);
3674 }
3675 
3676 #undef __FUNCT__
3677 #define __FUNCT__ "DMPlexRefine_CTetgen"
3678 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3679 {
3680   MPI_Comm       comm;
3681   const PetscInt dim  = 3;
3682   PLC           *in, *out;
3683   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3684   PetscMPIInt    rank;
3685   PetscErrorCode ierr;
3686 
3687   PetscFunctionBegin;
3688   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3689   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3690   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3691   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3692   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3693   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3694   ierr = PLCCreate(&in);CHKERRQ(ierr);
3695   ierr = PLCCreate(&out);CHKERRQ(ierr);
3696 
3697   in->numberofpoints = vEnd - vStart;
3698   if (in->numberofpoints > 0) {
3699     PetscSection coordSection;
3700     Vec          coordinates;
3701     PetscScalar *array;
3702 
3703     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3704     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3705     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3706     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3707     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3708     for (v = vStart; v < vEnd; ++v) {
3709       const PetscInt idx = v - vStart;
3710       PetscInt       off, d, m;
3711 
3712       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3713       for (d = 0; d < dim; ++d) {
3714         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3715       }
3716       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3717 
3718       in->pointmarkerlist[idx] = (int) m;
3719     }
3720     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3721   }
3722   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3723 
3724   in->numberofcorners       = 4;
3725   in->numberoftetrahedra    = cEnd - cStart;
3726   in->tetrahedronvolumelist = maxVolumes;
3727   if (in->numberoftetrahedra > 0) {
3728     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3729     for (c = cStart; c < cEnd; ++c) {
3730       const PetscInt idx      = c - cStart;
3731       PetscInt      *closure = NULL;
3732       PetscInt       closureSize;
3733 
3734       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3735       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3736       for (v = 0; v < 4; ++v) {
3737         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3738       }
3739       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3740     }
3741   }
3742   if (!rank) {
3743     TetGenOpts t;
3744 
3745     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3746 
3747     t.in        = dm; /* Should go away */
3748     t.refine    = 1;
3749     t.varvolume = 1;
3750     t.quality   = 1;
3751     t.edgesout  = 1;
3752     t.zeroindex = 1;
3753     t.quiet     = 1;
3754     t.verbose   = verbose; /* Change this */
3755 
3756     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3757     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3758   }
3759   {
3760     const PetscInt numCorners  = 4;
3761     const PetscInt numCells    = out->numberoftetrahedra;
3762     const PetscInt numVertices = out->numberofpoints;
3763     const int     *cells       = out->tetrahedronlist;
3764     const double  *meshCoords  = out->pointlist;
3765     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3766 
3767     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3768     /* Set labels */
3769     for (v = 0; v < numVertices; ++v) {
3770       if (out->pointmarkerlist[v]) {
3771         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3772       }
3773     }
3774     if (interpolate) {
3775       PetscInt e, f;
3776 
3777       for (e = 0; e < out->numberofedges; e++) {
3778         if (out->edgemarkerlist[e]) {
3779           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3780           const PetscInt *edges;
3781           PetscInt        numEdges;
3782 
3783           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3784           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3785           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3786           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3787         }
3788       }
3789       for (f = 0; f < out->numberoftrifaces; f++) {
3790         if (out->trifacemarkerlist[f]) {
3791           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3792           const PetscInt *faces;
3793           PetscInt        numFaces;
3794 
3795           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3796           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3797           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3798           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3799         }
3800       }
3801     }
3802     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3803   }
3804   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3805   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3806   PetscFunctionReturn(0);
3807 }
3808 #endif
3809 
3810 #undef __FUNCT__
3811 #define __FUNCT__ "DMPlexGenerate"
3812 /*@C
3813   DMPlexGenerate - Generates a mesh.
3814 
3815   Not Collective
3816 
3817   Input Parameters:
3818 + boundary - The DMPlex boundary object
3819 . name - The mesh generation package name
3820 - interpolate - Flag to create intermediate mesh elements
3821 
3822   Output Parameter:
3823 . mesh - The DMPlex object
3824 
3825   Level: intermediate
3826 
3827 .keywords: mesh, elements
3828 .seealso: DMPlexCreate(), DMRefine()
3829 @*/
3830 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3831 {
3832   PetscInt       dim;
3833   char           genname[1024];
3834   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
3835   PetscErrorCode ierr;
3836 
3837   PetscFunctionBegin;
3838   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
3839   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
3840   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
3841   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
3842   if (flg) name = genname;
3843   if (name) {
3844     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
3845     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
3846     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
3847   }
3848   switch (dim) {
3849   case 1:
3850     if (!name || isTriangle) {
3851 #if defined(PETSC_HAVE_TRIANGLE)
3852       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
3853 #else
3854       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
3855 #endif
3856     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
3857     break;
3858   case 2:
3859     if (!name || isCTetgen) {
3860 #if defined(PETSC_HAVE_CTETGEN)
3861       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3862 #else
3863       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
3864 #endif
3865     } else if (isTetgen) {
3866 #if defined(PETSC_HAVE_TETGEN)
3867       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3868 #else
3869       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
3870 #endif
3871     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
3872     break;
3873   default:
3874     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
3875   }
3876   PetscFunctionReturn(0);
3877 }
3878 
3879 typedef PetscInt CellRefiner;
3880 
3881 #undef __FUNCT__
3882 #define __FUNCT__ "GetDepthStart_Private"
3883 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
3884 {
3885   PetscFunctionBegin;
3886   if (cStart) *cStart = 0;
3887   if (vStart) *vStart = depthSize[depth];
3888   if (fStart) *fStart = depthSize[depth] + depthSize[0];
3889   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3890   PetscFunctionReturn(0);
3891 }
3892 
3893 #undef __FUNCT__
3894 #define __FUNCT__ "GetDepthEnd_Private"
3895 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
3896 {
3897   PetscFunctionBegin;
3898   if (cEnd) *cEnd = depthSize[depth];
3899   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
3900   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3901   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
3902   PetscFunctionReturn(0);
3903 }
3904 
3905 #undef __FUNCT__
3906 #define __FUNCT__ "CellRefinerGetSizes"
3907 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
3908 {
3909   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
3910   PetscErrorCode ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3914   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3915   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3916   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3917   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3918   switch (refiner) {
3919   case 1:
3920     /* Simplicial 2D */
3921     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
3922     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
3923     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
3924     break;
3925   case 3:
3926     /* Hybrid 2D */
3927     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3928     cMax = PetscMin(cEnd, cMax);
3929     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3930     fMax         = PetscMin(fEnd, fMax);
3931     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
3932     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 */
3933     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
3934     break;
3935   case 2:
3936     /* Hex 2D */
3937     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
3938     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
3939     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
3940     break;
3941   default:
3942     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3943   }
3944   PetscFunctionReturn(0);
3945 }
3946 
3947 #undef __FUNCT__
3948 #define __FUNCT__ "CellRefinerSetConeSizes"
3949 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3950 {
3951   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
3952   PetscErrorCode ierr;
3953 
3954   PetscFunctionBegin;
3955   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3956   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3957   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3958   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3959   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3960   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3961   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
3962   switch (refiner) {
3963   case 1:
3964     /* Simplicial 2D */
3965     /* All cells have 3 faces */
3966     for (c = cStart; c < cEnd; ++c) {
3967       for (r = 0; r < 4; ++r) {
3968         const PetscInt newp = (c - cStart)*4 + r;
3969 
3970         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
3971       }
3972     }
3973     /* Split faces have 2 vertices and the same cells as the parent */
3974     for (f = fStart; f < fEnd; ++f) {
3975       for (r = 0; r < 2; ++r) {
3976         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
3977         PetscInt       size;
3978 
3979         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
3980         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3981         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
3982       }
3983     }
3984     /* Interior faces have 2 vertices and 2 cells */
3985     for (c = cStart; c < cEnd; ++c) {
3986       for (r = 0; r < 3; ++r) {
3987         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
3988 
3989         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
3990         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
3991       }
3992     }
3993     /* Old vertices have identical supports */
3994     for (v = vStart; v < vEnd; ++v) {
3995       const PetscInt newp = vStartNew + (v - vStart);
3996       PetscInt       size;
3997 
3998       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3999       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4000     }
4001     /* Face vertices have 2 + cells*2 supports */
4002     for (f = fStart; f < fEnd; ++f) {
4003       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4004       PetscInt       size;
4005 
4006       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4007       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4008     }
4009     break;
4010   case 2:
4011     /* Hex 2D */
4012     /* All cells have 4 faces */
4013     for (c = cStart; c < cEnd; ++c) {
4014       for (r = 0; r < 4; ++r) {
4015         const PetscInt newp = (c - cStart)*4 + r;
4016 
4017         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4018       }
4019     }
4020     /* Split faces have 2 vertices and the same cells as the parent */
4021     for (f = fStart; f < fEnd; ++f) {
4022       for (r = 0; r < 2; ++r) {
4023         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4024         PetscInt       size;
4025 
4026         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4027         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4028         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4029       }
4030     }
4031     /* Interior faces have 2 vertices and 2 cells */
4032     for (c = cStart; c < cEnd; ++c) {
4033       for (r = 0; r < 4; ++r) {
4034         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4035 
4036         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4037         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4038       }
4039     }
4040     /* Old vertices have identical supports */
4041     for (v = vStart; v < vEnd; ++v) {
4042       const PetscInt newp = vStartNew + (v - vStart);
4043       PetscInt       size;
4044 
4045       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4046       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4047     }
4048     /* Face vertices have 2 + cells supports */
4049     for (f = fStart; f < fEnd; ++f) {
4050       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4051       PetscInt       size;
4052 
4053       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4054       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4055     }
4056     /* Cell vertices have 4 supports */
4057     for (c = cStart; c < cEnd; ++c) {
4058       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4059 
4060       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4061     }
4062     break;
4063   case 3:
4064     /* Hybrid 2D */
4065     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4066     cMax = PetscMin(cEnd, cMax);
4067     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4068     fMax = PetscMin(fEnd, fMax);
4069     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4070     /* Interior cells have 3 faces */
4071     for (c = cStart; c < cMax; ++c) {
4072       for (r = 0; r < 4; ++r) {
4073         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4074 
4075         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4076       }
4077     }
4078     /* Hybrid cells have 4 faces */
4079     for (c = cMax; c < cEnd; ++c) {
4080       for (r = 0; r < 2; ++r) {
4081         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4082 
4083         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4084       }
4085     }
4086     /* Interior split faces have 2 vertices and the same cells as the parent */
4087     for (f = fStart; f < fMax; ++f) {
4088       for (r = 0; r < 2; ++r) {
4089         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4090         PetscInt       size;
4091 
4092         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4093         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4094         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4095       }
4096     }
4097     /* Interior cell faces have 2 vertices and 2 cells */
4098     for (c = cStart; c < cMax; ++c) {
4099       for (r = 0; r < 3; ++r) {
4100         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4101 
4102         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4103         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4104       }
4105     }
4106     /* Hybrid faces have 2 vertices and the same cells */
4107     for (f = fMax; f < fEnd; ++f) {
4108       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4109       PetscInt       size;
4110 
4111       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4112       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4113       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4114     }
4115     /* Hybrid cell faces have 2 vertices and 2 cells */
4116     for (c = cMax; c < cEnd; ++c) {
4117       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4118 
4119       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4120       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4121     }
4122     /* Old vertices have identical supports */
4123     for (v = vStart; v < vEnd; ++v) {
4124       const PetscInt newp = vStartNew + (v - vStart);
4125       PetscInt       size;
4126 
4127       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4128       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4129     }
4130     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4131     for (f = fStart; f < fMax; ++f) {
4132       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4133       const PetscInt *support;
4134       PetscInt       size, newSize = 2, s;
4135 
4136       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4137       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4138       for (s = 0; s < size; ++s) {
4139         if (support[s] >= cMax) newSize += 1;
4140         else newSize += 2;
4141       }
4142       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4143     }
4144     break;
4145   default:
4146     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4147   }
4148   PetscFunctionReturn(0);
4149 }
4150 
4151 #undef __FUNCT__
4152 #define __FUNCT__ "CellRefinerSetCones"
4153 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4154 {
4155   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;
4156   PetscInt       maxSupportSize, *supportRef;
4157   PetscErrorCode ierr;
4158 
4159   PetscFunctionBegin;
4160   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4161   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4162   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4163   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4164   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4165   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4166   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4167   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4168   switch (refiner) {
4169   case 1:
4170     /* Simplicial 2D */
4171     /*
4172      2
4173      |\
4174      | \
4175      |  \
4176      |   \
4177      | C  \
4178      |     \
4179      |      \
4180      2---1---1
4181      |\  D  / \
4182      | 2   0   \
4183      |A \ /  B  \
4184      0---0-------1
4185      */
4186     /* All cells have 3 faces */
4187     for (c = cStart; c < cEnd; ++c) {
4188       const PetscInt  newp = cStartNew + (c - cStart)*4;
4189       const PetscInt *cone, *ornt;
4190       PetscInt        coneNew[3], orntNew[3];
4191 
4192       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4193       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4194       /* A triangle */
4195       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4196       orntNew[0] = ornt[0];
4197       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4198       orntNew[1] = -2;
4199       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4200       orntNew[2] = ornt[2];
4201       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4202       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4203 #if 1
4204       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);
4205       for (p = 0; p < 3; ++p) {
4206         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);
4207       }
4208 #endif
4209       /* B triangle */
4210       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4211       orntNew[0] = ornt[0];
4212       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4213       orntNew[1] = ornt[1];
4214       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4215       orntNew[2] = -2;
4216       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4217       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4218 #if 1
4219       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);
4220       for (p = 0; p < 3; ++p) {
4221         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);
4222       }
4223 #endif
4224       /* C triangle */
4225       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4226       orntNew[0] = -2;
4227       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4228       orntNew[1] = ornt[1];
4229       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4230       orntNew[2] = ornt[2];
4231       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4232       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4233 #if 1
4234       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);
4235       for (p = 0; p < 3; ++p) {
4236         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);
4237       }
4238 #endif
4239       /* D triangle */
4240       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4241       orntNew[0] = 0;
4242       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4243       orntNew[1] = 0;
4244       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4245       orntNew[2] = 0;
4246       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4247       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4248 #if 1
4249       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);
4250       for (p = 0; p < 3; ++p) {
4251         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);
4252       }
4253 #endif
4254     }
4255     /* Split faces have 2 vertices and the same cells as the parent */
4256     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4257     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4258     for (f = fStart; f < fEnd; ++f) {
4259       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4260 
4261       for (r = 0; r < 2; ++r) {
4262         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4263         const PetscInt *cone, *support;
4264         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4265 
4266         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4267         coneNew[0]       = vStartNew + (cone[0] - vStart);
4268         coneNew[1]       = vStartNew + (cone[1] - vStart);
4269         coneNew[(r+1)%2] = newv;
4270         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4271 #if 1
4272         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4273         for (p = 0; p < 2; ++p) {
4274           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);
4275         }
4276 #endif
4277         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4278         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4279         for (s = 0; s < supportSize; ++s) {
4280           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4281           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4282           for (c = 0; c < coneSize; ++c) {
4283             if (cone[c] == f) break;
4284           }
4285           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4286         }
4287         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4288 #if 1
4289         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4290         for (p = 0; p < supportSize; ++p) {
4291           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);
4292         }
4293 #endif
4294       }
4295     }
4296     /* Interior faces have 2 vertices and 2 cells */
4297     for (c = cStart; c < cEnd; ++c) {
4298       const PetscInt *cone;
4299 
4300       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4301       for (r = 0; r < 3; ++r) {
4302         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4303         PetscInt       coneNew[2];
4304         PetscInt       supportNew[2];
4305 
4306         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4307         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4308         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4309 #if 1
4310         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4311         for (p = 0; p < 2; ++p) {
4312           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);
4313         }
4314 #endif
4315         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4316         supportNew[1] = (c - cStart)*4 + 3;
4317         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4318 #if 1
4319         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4320         for (p = 0; p < 2; ++p) {
4321           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);
4322         }
4323 #endif
4324       }
4325     }
4326     /* Old vertices have identical supports */
4327     for (v = vStart; v < vEnd; ++v) {
4328       const PetscInt  newp = vStartNew + (v - vStart);
4329       const PetscInt *support, *cone;
4330       PetscInt        size, s;
4331 
4332       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4333       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4334       for (s = 0; s < size; ++s) {
4335         PetscInt r = 0;
4336 
4337         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4338         if (cone[1] == v) r = 1;
4339         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4340       }
4341       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4342 #if 1
4343       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4344       for (p = 0; p < size; ++p) {
4345         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);
4346       }
4347 #endif
4348     }
4349     /* Face vertices have 2 + cells*2 supports */
4350     for (f = fStart; f < fEnd; ++f) {
4351       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4352       const PetscInt *cone, *support;
4353       PetscInt        size, s;
4354 
4355       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4356       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4357       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4358       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4359       for (s = 0; s < size; ++s) {
4360         PetscInt r = 0;
4361 
4362         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4363         if      (cone[1] == f) r = 1;
4364         else if (cone[2] == f) r = 2;
4365         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4366         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4367       }
4368       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4369 #if 1
4370       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4371       for (p = 0; p < 2+size*2; ++p) {
4372         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);
4373       }
4374 #endif
4375     }
4376     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4377     break;
4378   case 2:
4379     /* Hex 2D */
4380     /*
4381      3---------2---------2
4382      |         |         |
4383      |    D    2    C    |
4384      |         |         |
4385      3----3----0----1----1
4386      |         |         |
4387      |    A    0    B    |
4388      |         |         |
4389      0---------0---------1
4390      */
4391     /* All cells have 4 faces */
4392     for (c = cStart; c < cEnd; ++c) {
4393       const PetscInt  newp = (c - cStart)*4;
4394       const PetscInt *cone, *ornt;
4395       PetscInt        coneNew[4], orntNew[4];
4396 
4397       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4398       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4399       /* A quad */
4400       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4401       orntNew[0] = ornt[0];
4402       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4403       orntNew[1] = 0;
4404       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4405       orntNew[2] = -2;
4406       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4407       orntNew[3] = ornt[3];
4408       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4409       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4410 #if 1
4411       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);
4412       for (p = 0; p < 4; ++p) {
4413         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);
4414       }
4415 #endif
4416       /* B quad */
4417       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4418       orntNew[0] = ornt[0];
4419       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4420       orntNew[1] = ornt[1];
4421       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4422       orntNew[2] = 0;
4423       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4424       orntNew[3] = -2;
4425       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4426       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4427 #if 1
4428       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);
4429       for (p = 0; p < 4; ++p) {
4430         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);
4431       }
4432 #endif
4433       /* C quad */
4434       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4435       orntNew[0] = -2;
4436       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4437       orntNew[1] = ornt[1];
4438       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4439       orntNew[2] = ornt[2];
4440       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4441       orntNew[3] = 0;
4442       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4443       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4444 #if 1
4445       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);
4446       for (p = 0; p < 4; ++p) {
4447         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);
4448       }
4449 #endif
4450       /* D quad */
4451       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4452       orntNew[0] = 0;
4453       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4454       orntNew[1] = -2;
4455       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4456       orntNew[2] = ornt[2];
4457       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4458       orntNew[3] = ornt[3];
4459       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4460       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4461 #if 1
4462       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);
4463       for (p = 0; p < 4; ++p) {
4464         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);
4465       }
4466 #endif
4467     }
4468     /* Split faces have 2 vertices and the same cells as the parent */
4469     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4470     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4471     for (f = fStart; f < fEnd; ++f) {
4472       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4473 
4474       for (r = 0; r < 2; ++r) {
4475         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4476         const PetscInt *cone, *support;
4477         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4478 
4479         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4480         coneNew[0]       = vStartNew + (cone[0] - vStart);
4481         coneNew[1]       = vStartNew + (cone[1] - vStart);
4482         coneNew[(r+1)%2] = newv;
4483         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4484 #if 1
4485         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4486         for (p = 0; p < 2; ++p) {
4487           if ((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);
4488         }
4489 #endif
4490         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4491         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4492         for (s = 0; s < supportSize; ++s) {
4493           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4494           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4495           for (c = 0; c < coneSize; ++c) {
4496             if (cone[c] == f) break;
4497           }
4498           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4499         }
4500         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4501 #if 1
4502         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4503         for (p = 0; p < supportSize; ++p) {
4504           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);
4505         }
4506 #endif
4507       }
4508     }
4509     /* Interior faces have 2 vertices and 2 cells */
4510     for (c = cStart; c < cEnd; ++c) {
4511       const PetscInt *cone;
4512       PetscInt        coneNew[2], supportNew[2];
4513 
4514       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4515       for (r = 0; r < 4; ++r) {
4516         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4517 
4518         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4519         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4520         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4521 #if 1
4522         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4523         for (p = 0; p < 2; ++p) {
4524           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);
4525         }
4526 #endif
4527         supportNew[0] = (c - cStart)*4 + r;
4528         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4529         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4530 #if 1
4531         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4532         for (p = 0; p < 2; ++p) {
4533           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);
4534         }
4535 #endif
4536       }
4537     }
4538     /* Old vertices have identical supports */
4539     for (v = vStart; v < vEnd; ++v) {
4540       const PetscInt  newp = vStartNew + (v - vStart);
4541       const PetscInt *support, *cone;
4542       PetscInt        size, s;
4543 
4544       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4545       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4546       for (s = 0; s < size; ++s) {
4547         PetscInt r = 0;
4548 
4549         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4550         if (cone[1] == v) r = 1;
4551         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4552       }
4553       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4554 #if 1
4555       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4556       for (p = 0; p < size; ++p) {
4557         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);
4558       }
4559 #endif
4560     }
4561     /* Face vertices have 2 + cells supports */
4562     for (f = fStart; f < fEnd; ++f) {
4563       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4564       const PetscInt *cone, *support;
4565       PetscInt        size, s;
4566 
4567       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4568       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4569       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4570       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4571       for (s = 0; s < size; ++s) {
4572         PetscInt r = 0;
4573 
4574         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4575         if      (cone[1] == f) r = 1;
4576         else if (cone[2] == f) r = 2;
4577         else if (cone[3] == f) r = 3;
4578         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4579       }
4580       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4581 #if 1
4582       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4583       for (p = 0; p < 2+size; ++p) {
4584         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);
4585       }
4586 #endif
4587     }
4588     /* Cell vertices have 4 supports */
4589     for (c = cStart; c < cEnd; ++c) {
4590       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4591       PetscInt       supportNew[4];
4592 
4593       for (r = 0; r < 4; ++r) {
4594         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4595       }
4596       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4597     }
4598     break;
4599   case 3:
4600     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4601     cMax = PetscMin(cEnd, cMax);
4602     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4603     fMax = PetscMin(fEnd, fMax);
4604     /* Interior cells have 3 faces */
4605     for (c = cStart; c < cMax; ++c) {
4606       const PetscInt  newp = cStartNew + (c - cStart)*4;
4607       const PetscInt *cone, *ornt;
4608       PetscInt        coneNew[3], orntNew[3];
4609 
4610       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4611       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4612       /* A triangle */
4613       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4614       orntNew[0] = ornt[0];
4615       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4616       orntNew[1] = -2;
4617       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4618       orntNew[2] = ornt[2];
4619       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4620       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4621 #if 1
4622       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);
4623       for (p = 0; p < 3; ++p) {
4624         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);
4625       }
4626 #endif
4627       /* B triangle */
4628       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4629       orntNew[0] = ornt[0];
4630       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4631       orntNew[1] = ornt[1];
4632       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4633       orntNew[2] = -2;
4634       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4635       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4636 #if 1
4637       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);
4638       for (p = 0; p < 3; ++p) {
4639         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);
4640       }
4641 #endif
4642       /* C triangle */
4643       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4644       orntNew[0] = -2;
4645       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4646       orntNew[1] = ornt[1];
4647       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4648       orntNew[2] = ornt[2];
4649       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4650       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4651 #if 1
4652       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);
4653       for (p = 0; p < 3; ++p) {
4654         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);
4655       }
4656 #endif
4657       /* D triangle */
4658       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4659       orntNew[0] = 0;
4660       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4661       orntNew[1] = 0;
4662       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4663       orntNew[2] = 0;
4664       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4665       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4666 #if 1
4667       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);
4668       for (p = 0; p < 3; ++p) {
4669         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);
4670       }
4671 #endif
4672     }
4673     /*
4674      2----3----3
4675      |         |
4676      |    B    |
4677      |         |
4678      0----4--- 1
4679      |         |
4680      |    A    |
4681      |         |
4682      0----2----1
4683      */
4684     /* Hybrid cells have 4 faces */
4685     for (c = cMax; c < cEnd; ++c) {
4686       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4687       const PetscInt *cone, *ornt;
4688       PetscInt        coneNew[4], orntNew[4];
4689 
4690       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4691       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4692       /* A quad */
4693       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4694       orntNew[0] = ornt[0];
4695       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4696       orntNew[1] = ornt[1];
4697       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4698       orntNew[2] = 0;
4699       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4700       orntNew[3] = 0;
4701       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4702       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4703 #if 1
4704       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);
4705       for (p = 0; p < 4; ++p) {
4706         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);
4707       }
4708 #endif
4709       /* B quad */
4710       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4711       orntNew[0] = ornt[0];
4712       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4713       orntNew[1] = ornt[1];
4714       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4715       orntNew[2] = 0;
4716       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4717       orntNew[3] = 0;
4718       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4719       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4720 #if 1
4721       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);
4722       for (p = 0; p < 4; ++p) {
4723         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);
4724       }
4725 #endif
4726     }
4727     /* Interior split faces have 2 vertices and the same cells as the parent */
4728     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4729     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4730     for (f = fStart; f < fMax; ++f) {
4731       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4732 
4733       for (r = 0; r < 2; ++r) {
4734         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4735         const PetscInt *cone, *support;
4736         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4737 
4738         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4739         coneNew[0]       = vStartNew + (cone[0] - vStart);
4740         coneNew[1]       = vStartNew + (cone[1] - vStart);
4741         coneNew[(r+1)%2] = newv;
4742         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4743 #if 1
4744         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4745         for (p = 0; p < 2; ++p) {
4746           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);
4747         }
4748 #endif
4749         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4750         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4751         for (s = 0; s < supportSize; ++s) {
4752           if (support[s] >= cMax) {
4753             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4754           } else {
4755             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4756             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4757             for (c = 0; c < coneSize; ++c) {
4758               if (cone[c] == f) break;
4759             }
4760             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4761           }
4762         }
4763         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4764 #if 1
4765         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4766         for (p = 0; p < supportSize; ++p) {
4767           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);
4768         }
4769 #endif
4770       }
4771     }
4772     /* Interior cell faces have 2 vertices and 2 cells */
4773     for (c = cStart; c < cMax; ++c) {
4774       const PetscInt *cone;
4775 
4776       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4777       for (r = 0; r < 3; ++r) {
4778         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4779         PetscInt       coneNew[2];
4780         PetscInt       supportNew[2];
4781 
4782         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4783         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4784         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4785 #if 1
4786         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4787         for (p = 0; p < 2; ++p) {
4788           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);
4789         }
4790 #endif
4791         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4792         supportNew[1] = (c - cStart)*4 + 3;
4793         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4794 #if 1
4795         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4796         for (p = 0; p < 2; ++p) {
4797           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);
4798         }
4799 #endif
4800       }
4801     }
4802     /* Interior hybrid faces have 2 vertices and the same cells */
4803     for (f = fMax; f < fEnd; ++f) {
4804       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4805       const PetscInt *cone;
4806       const PetscInt *support;
4807       PetscInt        coneNew[2];
4808       PetscInt        supportNew[2];
4809       PetscInt        size, s, r;
4810 
4811       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4812       coneNew[0] = vStartNew + (cone[0] - vStart);
4813       coneNew[1] = vStartNew + (cone[1] - vStart);
4814       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4815 #if 1
4816       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4817       for (p = 0; p < 2; ++p) {
4818         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);
4819       }
4820 #endif
4821       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4822       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4823       for (s = 0; s < size; ++s) {
4824         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4825         for (r = 0; r < 2; ++r) {
4826           if (cone[r+2] == f) break;
4827         }
4828         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4829       }
4830       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4831 #if 1
4832       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4833       for (p = 0; p < size; ++p) {
4834         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);
4835       }
4836 #endif
4837     }
4838     /* Cell hybrid faces have 2 vertices and 2 cells */
4839     for (c = cMax; c < cEnd; ++c) {
4840       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4841       const PetscInt *cone;
4842       PetscInt        coneNew[2];
4843       PetscInt        supportNew[2];
4844 
4845       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4846       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
4847       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
4848       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4849 #if 1
4850       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4851       for (p = 0; p < 2; ++p) {
4852         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);
4853       }
4854 #endif
4855       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
4856       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
4857       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4858 #if 1
4859       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4860       for (p = 0; p < 2; ++p) {
4861         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);
4862       }
4863 #endif
4864     }
4865     /* Old vertices have identical supports */
4866     for (v = vStart; v < vEnd; ++v) {
4867       const PetscInt  newp = vStartNew + (v - vStart);
4868       const PetscInt *support, *cone;
4869       PetscInt        size, s;
4870 
4871       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4872       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4873       for (s = 0; s < size; ++s) {
4874         if (support[s] >= fMax) {
4875           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
4876         } else {
4877           PetscInt r = 0;
4878 
4879           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4880           if (cone[1] == v) r = 1;
4881           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4882         }
4883       }
4884       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4885 #if 1
4886       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4887       for (p = 0; p < size; ++p) {
4888         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);
4889       }
4890 #endif
4891     }
4892     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4893     for (f = fStart; f < fMax; ++f) {
4894       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4895       const PetscInt *cone, *support;
4896       PetscInt        size, newSize = 2, s;
4897 
4898       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4899       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4900       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4901       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4902       for (s = 0; s < size; ++s) {
4903         PetscInt r = 0;
4904 
4905         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4906         if (support[s] >= cMax) {
4907           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
4908 
4909           newSize += 1;
4910         } else {
4911           if      (cone[1] == f) r = 1;
4912           else if (cone[2] == f) r = 2;
4913           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4914           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
4915 
4916           newSize += 2;
4917         }
4918       }
4919       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4920 #if 1
4921       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4922       for (p = 0; p < newSize; ++p) {
4923         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);
4924       }
4925 #endif
4926     }
4927     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4928     break;
4929   default:
4930     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4931   }
4932   PetscFunctionReturn(0);
4933 }
4934 
4935 #undef __FUNCT__
4936 #define __FUNCT__ "CellRefinerSetCoordinates"
4937 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4938 {
4939   PetscSection   coordSection, coordSectionNew;
4940   Vec            coordinates, coordinatesNew;
4941   PetscScalar   *coords, *coordsNew;
4942   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
4943   PetscErrorCode ierr;
4944 
4945   PetscFunctionBegin;
4946   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4947   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4948   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4949   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4950   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4951   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
4952   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
4953   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4954   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
4955   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
4956   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
4957   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
4958   if (fMax < 0) fMax = fEnd;
4959   switch (refiner) {
4960   case 1:
4961   case 2:
4962   case 3:
4963     /* Simplicial and Hex 2D */
4964     /* All vertices have the dim coordinates */
4965     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
4966       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
4967       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
4968     }
4969     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
4970     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
4971     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4972     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
4973     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
4974     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
4975     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
4976     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
4977     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4978     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4979     /* Old vertices have the same coordinates */
4980     for (v = vStart; v < vEnd; ++v) {
4981       const PetscInt newv = vStartNew + (v - vStart);
4982       PetscInt       off, offnew, d;
4983 
4984       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4985       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4986       for (d = 0; d < dim; ++d) {
4987         coordsNew[offnew+d] = coords[off+d];
4988       }
4989     }
4990     /* Face vertices have the average of endpoint coordinates */
4991     for (f = fStart; f < fMax; ++f) {
4992       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
4993       const PetscInt *cone;
4994       PetscInt        coneSize, offA, offB, offnew, d;
4995 
4996       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
4997       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
4998       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4999       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5000       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5001       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5002       for (d = 0; d < dim; ++d) {
5003         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5004       }
5005     }
5006     /* Just Hex 2D */
5007     if (refiner == 2) {
5008       /* Cell vertices have the average of corner coordinates */
5009       for (c = cStart; c < cEnd; ++c) {
5010         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5011         PetscInt      *cone = NULL;
5012         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5013 
5014         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5015         for (p = 0; p < closureSize*2; p += 2) {
5016           const PetscInt point = cone[p];
5017           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5018         }
5019         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5020         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5021         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5022         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5023         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5024         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5025         for (d = 0; d < dim; ++d) {
5026           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5027         }
5028         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5029       }
5030     }
5031     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5032     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5033     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5034     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5035     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5036     break;
5037   default:
5038     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5039   }
5040   PetscFunctionReturn(0);
5041 }
5042 
5043 #undef __FUNCT__
5044 #define __FUNCT__ "DMPlexCreateProcessSF"
5045 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5046 {
5047   PetscInt           numRoots, numLeaves, l;
5048   const PetscInt    *localPoints;
5049   const PetscSFNode *remotePoints;
5050   PetscInt          *localPointsNew;
5051   PetscSFNode       *remotePointsNew;
5052   PetscInt          *ranks, *ranksNew;
5053   PetscErrorCode     ierr;
5054 
5055   PetscFunctionBegin;
5056   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5057   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5058   for (l = 0; l < numLeaves; ++l) {
5059     ranks[l] = remotePoints[l].rank;
5060   }
5061   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5062   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5063   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5064   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5065   for (l = 0; l < numLeaves; ++l) {
5066     ranksNew[l]              = ranks[l];
5067     localPointsNew[l]        = l;
5068     remotePointsNew[l].index = 0;
5069     remotePointsNew[l].rank  = ranksNew[l];
5070   }
5071   ierr = PetscFree(ranks);CHKERRQ(ierr);
5072   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5073   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5074   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5075   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5076   PetscFunctionReturn(0);
5077 }
5078 
5079 #undef __FUNCT__
5080 #define __FUNCT__ "CellRefinerCreateSF"
5081 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5082 {
5083   PetscSF            sf, sfNew, sfProcess;
5084   IS                 processRanks;
5085   MPI_Datatype       depthType;
5086   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5087   const PetscInt    *localPoints, *neighbors;
5088   const PetscSFNode *remotePoints;
5089   PetscInt          *localPointsNew;
5090   PetscSFNode       *remotePointsNew;
5091   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5092   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5093   PetscErrorCode     ierr;
5094 
5095   PetscFunctionBegin;
5096   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5097   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5098   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5099   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5100   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5101   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5102   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5103   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5104   switch (refiner) {
5105   case 3:
5106     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5107     cMax = PetscMin(cEnd, cMax);
5108     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5109     fMax = PetscMin(fEnd, fMax);
5110   }
5111   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5112   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5113   /* Caculate size of new SF */
5114   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5115   if (numRoots < 0) PetscFunctionReturn(0);
5116   for (l = 0; l < numLeaves; ++l) {
5117     const PetscInt p = localPoints[l];
5118 
5119     switch (refiner) {
5120     case 1:
5121       /* Simplicial 2D */
5122       if ((p >= vStart) && (p < vEnd)) {
5123         /* Old vertices stay the same */
5124         ++numLeavesNew;
5125       } else if ((p >= fStart) && (p < fEnd)) {
5126         /* Old faces add new faces and vertex */
5127         numLeavesNew += 1 + 2;
5128       } else if ((p >= cStart) && (p < cEnd)) {
5129         /* Old cells add new cells and interior faces */
5130         numLeavesNew += 4 + 3;
5131       }
5132       break;
5133     case 2:
5134       /* Hex 2D */
5135       if ((p >= vStart) && (p < vEnd)) {
5136         /* Old vertices stay the same */
5137         ++numLeavesNew;
5138       } else if ((p >= fStart) && (p < fEnd)) {
5139         /* Old faces add new faces and vertex */
5140         numLeavesNew += 1 + 2;
5141       } else if ((p >= cStart) && (p < cEnd)) {
5142         /* Old cells add new cells and interior faces */
5143         numLeavesNew += 4 + 4;
5144       }
5145       break;
5146     default:
5147       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5148     }
5149   }
5150   /* Communicate depthSizes for each remote rank */
5151   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5152   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5153   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5154   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);
5155   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5156   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5157   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5158   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5159   for (n = 0; n < numNeighbors; ++n) {
5160     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5161   }
5162   depthSizeOld[depth]   = cMax;
5163   depthSizeOld[0]       = vMax;
5164   depthSizeOld[depth-1] = fMax;
5165   depthSizeOld[1]       = eMax;
5166 
5167   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5168   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5169 
5170   depthSizeOld[depth]   = cEnd - cStart;
5171   depthSizeOld[0]       = vEnd - vStart;
5172   depthSizeOld[depth-1] = fEnd - fStart;
5173   depthSizeOld[1]       = eEnd - eStart;
5174 
5175   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5176   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5177   for (n = 0; n < numNeighbors; ++n) {
5178     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5179   }
5180   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5181   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5182   /* Calculate new point SF */
5183   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5184   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5185   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5186   for (l = 0, m = 0; l < numLeaves; ++l) {
5187     PetscInt    p     = localPoints[l];
5188     PetscInt    rp    = remotePoints[l].index, n;
5189     PetscMPIInt rrank = remotePoints[l].rank;
5190 
5191     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5192     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5193     switch (refiner) {
5194     case 1:
5195       /* Simplicial 2D */
5196       if ((p >= vStart) && (p < vEnd)) {
5197         /* Old vertices stay the same */
5198         localPointsNew[m]        = vStartNew     + (p  - vStart);
5199         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5200         remotePointsNew[m].rank  = rrank;
5201         ++m;
5202       } else if ((p >= fStart) && (p < fEnd)) {
5203         /* Old faces add new faces and vertex */
5204         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5205         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5206         remotePointsNew[m].rank  = rrank;
5207         ++m;
5208         for (r = 0; r < 2; ++r, ++m) {
5209           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5210           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5211           remotePointsNew[m].rank  = rrank;
5212         }
5213       } else if ((p >= cStart) && (p < cEnd)) {
5214         /* Old cells add new cells and interior faces */
5215         for (r = 0; r < 4; ++r, ++m) {
5216           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5217           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5218           remotePointsNew[m].rank  = rrank;
5219         }
5220         for (r = 0; r < 3; ++r, ++m) {
5221           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5222           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5223           remotePointsNew[m].rank  = rrank;
5224         }
5225       }
5226       break;
5227     case 2:
5228       /* Hex 2D */
5229       if ((p >= vStart) && (p < vEnd)) {
5230         /* Old vertices stay the same */
5231         localPointsNew[m]        = vStartNew     + (p  - vStart);
5232         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5233         remotePointsNew[m].rank  = rrank;
5234         ++m;
5235       } else if ((p >= fStart) && (p < fEnd)) {
5236         /* Old faces add new faces and vertex */
5237         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5238         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5239         remotePointsNew[m].rank  = rrank;
5240         ++m;
5241         for (r = 0; r < 2; ++r, ++m) {
5242           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5243           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5244           remotePointsNew[m].rank  = rrank;
5245         }
5246       } else if ((p >= cStart) && (p < cEnd)) {
5247         /* Old cells add new cells and interior faces */
5248         for (r = 0; r < 4; ++r, ++m) {
5249           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5250           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5251           remotePointsNew[m].rank  = rrank;
5252         }
5253         for (r = 0; r < 4; ++r, ++m) {
5254           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5255           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5256           remotePointsNew[m].rank  = rrank;
5257         }
5258       }
5259       break;
5260     case 3:
5261       /* Hybrid simplicial 2D */
5262       if ((p >= vStart) && (p < vEnd)) {
5263         /* Old vertices stay the same */
5264         localPointsNew[m]        = vStartNew     + (p  - vStart);
5265         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5266         remotePointsNew[m].rank  = rrank;
5267         ++m;
5268       } else if ((p >= fStart) && (p < fMax)) {
5269         /* Old interior faces add new faces and vertex */
5270         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5271         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5272         remotePointsNew[m].rank  = rrank;
5273         ++m;
5274         for (r = 0; r < 2; ++r, ++m) {
5275           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5276           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5277           remotePointsNew[m].rank  = rrank;
5278         }
5279       } else if ((p >= fMax) && (p < fEnd)) {
5280         /* Old hybrid faces stay the same */
5281         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5282         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5283         remotePointsNew[m].rank  = rrank;
5284         ++m;
5285       } else if ((p >= cStart) && (p < cMax)) {
5286         /* Old interior cells add new cells and interior faces */
5287         for (r = 0; r < 4; ++r, ++m) {
5288           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5289           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5290           remotePointsNew[m].rank  = rrank;
5291         }
5292         for (r = 0; r < 3; ++r, ++m) {
5293           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5294           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5295           remotePointsNew[m].rank  = rrank;
5296         }
5297       } else if ((p >= cStart) && (p < cMax)) {
5298         /* Old hybrid cells add new cells and hybrid face */
5299         for (r = 0; r < 2; ++r, ++m) {
5300           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5301           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5302           remotePointsNew[m].rank  = rrank;
5303         }
5304         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5305         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]);
5306         remotePointsNew[m].rank  = rrank;
5307         ++m;
5308       }
5309       break;
5310     default:
5311       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5312     }
5313   }
5314   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5315   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5316   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5317   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5318   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5319   PetscFunctionReturn(0);
5320 }
5321 
5322 #undef __FUNCT__
5323 #define __FUNCT__ "CellRefinerCreateLabels"
5324 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5325 {
5326   PetscInt       numLabels, l;
5327   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5328   PetscErrorCode ierr;
5329 
5330   PetscFunctionBegin;
5331   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5332   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5333   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5334   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5335 
5336   cStartNew = 0;
5337   vStartNew = depthSize[2];
5338   fStartNew = depthSize[2] + depthSize[0];
5339 
5340   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5341   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5342   switch (refiner) {
5343   case 3:
5344     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5345     cMax = PetscMin(cEnd, cMax);
5346     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5347     fMax = PetscMin(fEnd, fMax);
5348   }
5349   for (l = 0; l < numLabels; ++l) {
5350     DMLabel         label, labelNew;
5351     const char     *lname;
5352     PetscBool       isDepth;
5353     IS              valueIS;
5354     const PetscInt *values;
5355     PetscInt        numValues, val;
5356 
5357     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5358     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5359     if (isDepth) continue;
5360     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5361     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5362     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5363     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5364     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5365     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5366     for (val = 0; val < numValues; ++val) {
5367       IS              pointIS;
5368       const PetscInt *points;
5369       PetscInt        numPoints, n;
5370 
5371       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5372       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5373       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5374       for (n = 0; n < numPoints; ++n) {
5375         const PetscInt p = points[n];
5376         switch (refiner) {
5377         case 1:
5378           /* Simplicial 2D */
5379           if ((p >= vStart) && (p < vEnd)) {
5380             /* Old vertices stay the same */
5381             newp = vStartNew + (p - vStart);
5382             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5383           } else if ((p >= fStart) && (p < fEnd)) {
5384             /* Old faces add new faces and vertex */
5385             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5386             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5387             for (r = 0; r < 2; ++r) {
5388               newp = fStartNew + (p - fStart)*2 + r;
5389               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5390             }
5391           } else if ((p >= cStart) && (p < cEnd)) {
5392             /* Old cells add new cells and interior faces */
5393             for (r = 0; r < 4; ++r) {
5394               newp = cStartNew + (p - cStart)*4 + r;
5395               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5396             }
5397             for (r = 0; r < 3; ++r) {
5398               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5399               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5400             }
5401           }
5402           break;
5403         case 2:
5404           /* Hex 2D */
5405           if ((p >= vStart) && (p < vEnd)) {
5406             /* Old vertices stay the same */
5407             newp = vStartNew + (p - vStart);
5408             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5409           } else if ((p >= fStart) && (p < fEnd)) {
5410             /* Old faces add new faces and vertex */
5411             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5412             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5413             for (r = 0; r < 2; ++r) {
5414               newp = fStartNew + (p - fStart)*2 + r;
5415               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5416             }
5417           } else if ((p >= cStart) && (p < cEnd)) {
5418             /* Old cells add new cells and interior faces and vertex */
5419             for (r = 0; r < 4; ++r) {
5420               newp = cStartNew + (p - cStart)*4 + r;
5421               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5422             }
5423             for (r = 0; r < 4; ++r) {
5424               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5425               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5426             }
5427             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5428             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5429           }
5430           break;
5431         case 3:
5432           /* Hybrid simplicial 2D */
5433           if ((p >= vStart) && (p < vEnd)) {
5434             /* Old vertices stay the same */
5435             newp = vStartNew + (p - vStart);
5436             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5437           } else if ((p >= fStart) && (p < fMax)) {
5438             /* Old interior faces add new faces and vertex */
5439             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5440             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5441             for (r = 0; r < 2; ++r) {
5442               newp = fStartNew + (p - fStart)*2 + r;
5443               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5444             }
5445           } else if ((p >= fMax) && (p < fEnd)) {
5446             /* Old hybrid faces stay the same */
5447             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5448             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5449           } else if ((p >= cStart) && (p < cMax)) {
5450             /* Old interior cells add new cells and interior faces */
5451             for (r = 0; r < 4; ++r) {
5452               newp = cStartNew + (p - cStart)*4 + r;
5453               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5454             }
5455             for (r = 0; r < 3; ++r) {
5456               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5457               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5458             }
5459           } else if ((p >= cMax) && (p < cEnd)) {
5460             /* Old hybrid cells add new cells and hybrid face */
5461             for (r = 0; r < 2; ++r) {
5462               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5463               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5464             }
5465             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5466             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5467           }
5468           break;
5469         default:
5470           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5471         }
5472       }
5473       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5474       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5475     }
5476     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5477     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5478     if (0) {
5479       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5480       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5481       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5482     }
5483   }
5484   PetscFunctionReturn(0);
5485 }
5486 
5487 #undef __FUNCT__
5488 #define __FUNCT__ "DMPlexRefine_Uniform"
5489 /* This will only work for interpolated meshes */
5490 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5491 {
5492   DM             rdm;
5493   PetscInt      *depthSize;
5494   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5495   PetscErrorCode ierr;
5496 
5497   PetscFunctionBegin;
5498   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5499   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5500   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5501   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5502   /* Calculate number of new points of each depth */
5503   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5504   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5505   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5506   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5507   /* Step 1: Set chart */
5508   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5509   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5510   /* Step 2: Set cone/support sizes */
5511   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5512   /* Step 3: Setup refined DM */
5513   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5514   /* Step 4: Set cones and supports */
5515   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5516   /* Step 5: Stratify */
5517   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5518   /* Step 6: Set coordinates for vertices */
5519   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5520   /* Step 7: Create pointSF */
5521   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5522   /* Step 8: Create labels */
5523   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5524   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5525 
5526   *dmRefined = rdm;
5527   PetscFunctionReturn(0);
5528 }
5529 
5530 #undef __FUNCT__
5531 #define __FUNCT__ "DMPlexSetRefinementUniform"
5532 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5533 {
5534   DM_Plex *mesh = (DM_Plex*) dm->data;
5535 
5536   PetscFunctionBegin;
5537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5538   mesh->refinementUniform = refinementUniform;
5539   PetscFunctionReturn(0);
5540 }
5541 
5542 #undef __FUNCT__
5543 #define __FUNCT__ "DMPlexGetRefinementUniform"
5544 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5545 {
5546   DM_Plex *mesh = (DM_Plex*) dm->data;
5547 
5548   PetscFunctionBegin;
5549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5550   PetscValidPointer(refinementUniform,  2);
5551   *refinementUniform = mesh->refinementUniform;
5552   PetscFunctionReturn(0);
5553 }
5554 
5555 #undef __FUNCT__
5556 #define __FUNCT__ "DMPlexSetRefinementLimit"
5557 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5558 {
5559   DM_Plex *mesh = (DM_Plex*) dm->data;
5560 
5561   PetscFunctionBegin;
5562   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5563   mesh->refinementLimit = refinementLimit;
5564   PetscFunctionReturn(0);
5565 }
5566 
5567 #undef __FUNCT__
5568 #define __FUNCT__ "DMPlexGetRefinementLimit"
5569 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5570 {
5571   DM_Plex *mesh = (DM_Plex*) dm->data;
5572 
5573   PetscFunctionBegin;
5574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5575   PetscValidPointer(refinementLimit,  2);
5576   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5577   *refinementLimit = mesh->refinementLimit;
5578   PetscFunctionReturn(0);
5579 }
5580 
5581 #undef __FUNCT__
5582 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5583 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5584 {
5585   PetscInt       dim, cStart, coneSize, cMax;
5586   PetscErrorCode ierr;
5587 
5588   PetscFunctionBegin;
5589   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5590   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5591   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5592   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5593   switch (dim) {
5594   case 2:
5595     switch (coneSize) {
5596     case 3:
5597       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5598       else *cellRefiner = 1; /* Triangular */
5599       break;
5600     case 4:
5601       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5602       else *cellRefiner = 2; /* Quadrilateral */
5603       break;
5604     default:
5605       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5606     }
5607     break;
5608   default:
5609     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5610   }
5611   PetscFunctionReturn(0);
5612 }
5613 
5614 #undef __FUNCT__
5615 #define __FUNCT__ "DMRefine_Plex"
5616 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5617 {
5618   PetscReal      refinementLimit;
5619   PetscInt       dim, cStart, cEnd;
5620   char           genname[1024], *name = NULL;
5621   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5622   PetscErrorCode ierr;
5623 
5624   PetscFunctionBegin;
5625   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5626   if (isUniform) {
5627     CellRefiner cellRefiner;
5628 
5629     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5630     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5631     PetscFunctionReturn(0);
5632   }
5633   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5634   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5635   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5636   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5637   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5638   if (flg) name = genname;
5639   if (name) {
5640     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5641     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5642     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5643   }
5644   switch (dim) {
5645   case 2:
5646     if (!name || isTriangle) {
5647 #if defined(PETSC_HAVE_TRIANGLE)
5648       double  *maxVolumes;
5649       PetscInt c;
5650 
5651       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5652       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5653       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5654 #else
5655       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5656 #endif
5657     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5658     break;
5659   case 3:
5660     if (!name || isCTetgen) {
5661 #if defined(PETSC_HAVE_CTETGEN)
5662       PetscReal *maxVolumes;
5663       PetscInt   c;
5664 
5665       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5666       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5667       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5668 #else
5669       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5670 #endif
5671     } else if (isTetgen) {
5672 #if defined(PETSC_HAVE_TETGEN)
5673       double  *maxVolumes;
5674       PetscInt c;
5675 
5676       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5677       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5678       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5679 #else
5680       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5681 #endif
5682     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5683     break;
5684   default:
5685     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5686   }
5687   PetscFunctionReturn(0);
5688 }
5689 
5690 #undef __FUNCT__
5691 #define __FUNCT__ "DMPlexGetDepth"
5692 /*@
5693   DMPlexGetDepth - get the number of strata
5694 
5695   Not Collective
5696 
5697   Input Parameters:
5698 . dm           - The DMPlex object
5699 
5700   Output Parameters:
5701 . depth - number of strata
5702 
5703   Level: developer
5704 
5705   Notes:
5706   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
5707 
5708 .keywords: mesh, points
5709 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5710 @*/
5711 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5712 {
5713   PetscInt       d;
5714   PetscErrorCode ierr;
5715 
5716   PetscFunctionBegin;
5717   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5718   PetscValidPointer(depth, 2);
5719   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
5720   *depth = d-1;
5721   PetscFunctionReturn(0);
5722 }
5723 
5724 #undef __FUNCT__
5725 #define __FUNCT__ "DMPlexGetDepthStratum"
5726 /*@
5727   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5728 
5729   Not Collective
5730 
5731   Input Parameters:
5732 + dm           - The DMPlex object
5733 - stratumValue - The requested depth
5734 
5735   Output Parameters:
5736 + start - The first point at this depth
5737 - end   - One beyond the last point at this depth
5738 
5739   Level: developer
5740 
5741 .keywords: mesh, points
5742 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5743 @*/
5744 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5745 {
5746   DM_Plex       *mesh = (DM_Plex*) dm->data;
5747   DMLabel        next  = mesh->labels;
5748   PetscBool      flg   = PETSC_FALSE;
5749   PetscInt       depth;
5750   PetscErrorCode ierr;
5751 
5752   PetscFunctionBegin;
5753   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5754   if (stratumValue < 0) {
5755     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5756     PetscFunctionReturn(0);
5757   } else {
5758     PetscInt pStart, pEnd;
5759 
5760     if (start) *start = 0;
5761     if (end)   *end   = 0;
5762     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5763     if (pStart == pEnd) PetscFunctionReturn(0);
5764   }
5765   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5766   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5767   /* We should have a generic GetLabel() and a Label class */
5768   while (next) {
5769     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5770     if (flg) break;
5771     next = next->next;
5772   }
5773   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5774   depth = stratumValue;
5775   if ((depth < 0) || (depth >= next->numStrata)) {
5776     if (start) *start = 0;
5777     if (end)   *end   = 0;
5778   } else {
5779     if (start) *start = next->points[next->stratumOffsets[depth]];
5780     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5781   }
5782   PetscFunctionReturn(0);
5783 }
5784 
5785 #undef __FUNCT__
5786 #define __FUNCT__ "DMPlexGetHeightStratum"
5787 /*@
5788   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5789 
5790   Not Collective
5791 
5792   Input Parameters:
5793 + dm           - The DMPlex object
5794 - stratumValue - The requested height
5795 
5796   Output Parameters:
5797 + start - The first point at this height
5798 - end   - One beyond the last point at this height
5799 
5800   Level: developer
5801 
5802 .keywords: mesh, points
5803 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5804 @*/
5805 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5806 {
5807   DM_Plex       *mesh = (DM_Plex*) dm->data;
5808   DMLabel        next  = mesh->labels;
5809   PetscBool      flg   = PETSC_FALSE;
5810   PetscInt       depth;
5811   PetscErrorCode ierr;
5812 
5813   PetscFunctionBegin;
5814   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5815   if (stratumValue < 0) {
5816     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5817   } else {
5818     PetscInt pStart, pEnd;
5819 
5820     if (start) *start = 0;
5821     if (end)   *end   = 0;
5822     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5823     if (pStart == pEnd) PetscFunctionReturn(0);
5824   }
5825   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5826   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5827   /* We should have a generic GetLabel() and a Label class */
5828   while (next) {
5829     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5830     if (flg) break;
5831     next = next->next;
5832   }
5833   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5834   depth = next->stratumValues[next->numStrata-1] - stratumValue;
5835   if ((depth < 0) || (depth >= next->numStrata)) {
5836     if (start) *start = 0;
5837     if (end)   *end   = 0;
5838   } else {
5839     if (start) *start = next->points[next->stratumOffsets[depth]];
5840     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5841   }
5842   PetscFunctionReturn(0);
5843 }
5844 
5845 #undef __FUNCT__
5846 #define __FUNCT__ "DMPlexCreateSectionInitial"
5847 /* Set the number of dof on each point and separate by fields */
5848 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
5849 {
5850   PetscInt      *numDofTot;
5851   PetscInt       pStart = 0, pEnd = 0;
5852   PetscInt       p, d, f;
5853   PetscErrorCode ierr;
5854 
5855   PetscFunctionBegin;
5856   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
5857   for (d = 0; d <= dim; ++d) {
5858     numDofTot[d] = 0;
5859     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
5860   }
5861   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
5862   if (numFields > 0) {
5863     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
5864     if (numComp) {
5865       for (f = 0; f < numFields; ++f) {
5866         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
5867       }
5868     }
5869   }
5870   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5871   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
5872   for (d = 0; d <= dim; ++d) {
5873     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
5874     for (p = pStart; p < pEnd; ++p) {
5875       for (f = 0; f < numFields; ++f) {
5876         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
5877       }
5878       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
5879     }
5880   }
5881   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
5882   PetscFunctionReturn(0);
5883 }
5884 
5885 #undef __FUNCT__
5886 #define __FUNCT__ "DMPlexCreateSectionBCDof"
5887 /* Set the number of dof on each point and separate by fields
5888    If constDof is PETSC_DETERMINE, constrain every dof on the point
5889 */
5890 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
5891 {
5892   PetscInt       numFields;
5893   PetscInt       bc;
5894   PetscErrorCode ierr;
5895 
5896   PetscFunctionBegin;
5897   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5898   for (bc = 0; bc < numBC; ++bc) {
5899     PetscInt        field = 0;
5900     const PetscInt *idx;
5901     PetscInt        n, i;
5902 
5903     if (numFields) field = bcField[bc];
5904     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
5905     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5906     for (i = 0; i < n; ++i) {
5907       const PetscInt p        = idx[i];
5908       PetscInt       numConst = constDof;
5909 
5910       /* Constrain every dof on the point */
5911       if (numConst < 0) {
5912         if (numFields) {
5913           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
5914         } else {
5915           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
5916         }
5917       }
5918       if (numFields) {
5919         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
5920       }
5921       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
5922     }
5923     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5924   }
5925   PetscFunctionReturn(0);
5926 }
5927 
5928 #undef __FUNCT__
5929 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
5930 /* Set the constrained indices on each point and separate by fields */
5931 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
5932 {
5933   PetscInt      *maxConstraints;
5934   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
5935   PetscErrorCode ierr;
5936 
5937   PetscFunctionBegin;
5938   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5939   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5940   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
5941   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
5942   for (p = pStart; p < pEnd; ++p) {
5943     PetscInt cdof;
5944 
5945     if (numFields) {
5946       for (f = 0; f < numFields; ++f) {
5947         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
5948         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
5949       }
5950     } else {
5951       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
5952       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
5953     }
5954   }
5955   for (f = 0; f < numFields; ++f) {
5956     maxConstraints[numFields] += maxConstraints[f];
5957   }
5958   if (maxConstraints[numFields]) {
5959     PetscInt *indices;
5960 
5961     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
5962     for (p = pStart; p < pEnd; ++p) {
5963       PetscInt cdof, d;
5964 
5965       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
5966       if (cdof) {
5967         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
5968         if (numFields) {
5969           PetscInt numConst = 0, foff = 0;
5970 
5971           for (f = 0; f < numFields; ++f) {
5972             PetscInt cfdof, fdof;
5973 
5974             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
5975             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
5976             /* Change constraint numbering from absolute local dof number to field relative local dof number */
5977             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
5978             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
5979             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
5980             numConst += cfdof;
5981             foff     += fdof;
5982           }
5983           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
5984         } else {
5985           for (d = 0; d < cdof; ++d) indices[d] = d;
5986         }
5987         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
5988       }
5989     }
5990     ierr = PetscFree(indices);CHKERRQ(ierr);
5991   }
5992   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
5993   PetscFunctionReturn(0);
5994 }
5995 
5996 #undef __FUNCT__
5997 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
5998 /* Set the constrained field indices on each point */
5999 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6000 {
6001   const PetscInt *points, *indices;
6002   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6003   PetscErrorCode  ierr;
6004 
6005   PetscFunctionBegin;
6006   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6007   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6008 
6009   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6010   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6011   if (!constraintIndices) {
6012     PetscInt *idx, i;
6013 
6014     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6015     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6016     for (i = 0; i < maxDof; ++i) idx[i] = i;
6017     for (p = 0; p < numPoints; ++p) {
6018       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6019     }
6020     ierr = PetscFree(idx);CHKERRQ(ierr);
6021   } else {
6022     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6023     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6024     for (p = 0; p < numPoints; ++p) {
6025       PetscInt fcdof;
6026 
6027       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6028       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);
6029       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6030     }
6031     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6032   }
6033   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6034   PetscFunctionReturn(0);
6035 }
6036 
6037 #undef __FUNCT__
6038 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6039 /* Set the constrained indices on each point and separate by fields */
6040 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6041 {
6042   PetscInt      *indices;
6043   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6044   PetscErrorCode ierr;
6045 
6046   PetscFunctionBegin;
6047   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6048   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6049   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6050   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6051   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6052   for (p = pStart; p < pEnd; ++p) {
6053     PetscInt cdof, d;
6054 
6055     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6056     if (cdof) {
6057       PetscInt numConst = 0, foff = 0;
6058 
6059       for (f = 0; f < numFields; ++f) {
6060         const PetscInt *fcind;
6061         PetscInt        fdof, fcdof;
6062 
6063         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6064         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6065         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6066         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6067         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6068         foff     += fdof;
6069         numConst += fcdof;
6070       }
6071       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6072       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6073     }
6074   }
6075   ierr = PetscFree(indices);CHKERRQ(ierr);
6076   PetscFunctionReturn(0);
6077 }
6078 
6079 #undef __FUNCT__
6080 #define __FUNCT__ "DMPlexCreateSection"
6081 /*@C
6082   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6083 
6084   Not Collective
6085 
6086   Input Parameters:
6087 + dm        - The DMPlex object
6088 . dim       - The spatial dimension of the problem
6089 . numFields - The number of fields in the problem
6090 . numComp   - An array of size numFields that holds the number of components for each field
6091 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6092 . numBC     - The number of boundary conditions
6093 . bcField   - An array of size numBC giving the field number for each boundry condition
6094 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6095 
6096   Output Parameter:
6097 . section - The PetscSection object
6098 
6099   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
6100   nubmer of dof for field 0 on each edge.
6101 
6102   Level: developer
6103 
6104   Fortran Notes:
6105   A Fortran 90 version is available as DMPlexCreateSectionF90()
6106 
6107 .keywords: mesh, elements
6108 .seealso: DMPlexCreate(), PetscSectionCreate()
6109 @*/
6110 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6111 {
6112   PetscErrorCode ierr;
6113 
6114   PetscFunctionBegin;
6115   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6116   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6117   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6118   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6119   {
6120     PetscBool view = PETSC_FALSE;
6121 
6122     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6123     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6124   }
6125   PetscFunctionReturn(0);
6126 }
6127 
6128 #undef __FUNCT__
6129 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6130 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6131 {
6132   PetscSection   section;
6133   PetscErrorCode ierr;
6134 
6135   PetscFunctionBegin;
6136   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6137   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6138   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6139   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6140   PetscFunctionReturn(0);
6141 }
6142 
6143 #undef __FUNCT__
6144 #define __FUNCT__ "DMPlexGetCoordinateSection"
6145 /*@
6146   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6147 
6148   Not Collective
6149 
6150   Input Parameter:
6151 . dm - The DMPlex object
6152 
6153   Output Parameter:
6154 . section - The PetscSection object
6155 
6156   Level: intermediate
6157 
6158 .keywords: mesh, coordinates
6159 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6160 @*/
6161 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6162 {
6163   DM             cdm;
6164   PetscErrorCode ierr;
6165 
6166   PetscFunctionBegin;
6167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6168   PetscValidPointer(section, 2);
6169   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6170   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6171   PetscFunctionReturn(0);
6172 }
6173 
6174 #undef __FUNCT__
6175 #define __FUNCT__ "DMPlexSetCoordinateSection"
6176 /*@
6177   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6178 
6179   Not Collective
6180 
6181   Input Parameters:
6182 + dm      - The DMPlex object
6183 - section - The PetscSection object
6184 
6185   Level: intermediate
6186 
6187 .keywords: mesh, coordinates
6188 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6189 @*/
6190 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6191 {
6192   DM             cdm;
6193   PetscErrorCode ierr;
6194 
6195   PetscFunctionBegin;
6196   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6197   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6198   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6199   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6200   PetscFunctionReturn(0);
6201 }
6202 
6203 #undef __FUNCT__
6204 #define __FUNCT__ "DMPlexGetConeSection"
6205 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6206 {
6207   DM_Plex *mesh = (DM_Plex*) dm->data;
6208 
6209   PetscFunctionBegin;
6210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6211   if (section) *section = mesh->coneSection;
6212   PetscFunctionReturn(0);
6213 }
6214 
6215 #undef __FUNCT__
6216 #define __FUNCT__ "DMPlexGetCones"
6217 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6218 {
6219   DM_Plex *mesh = (DM_Plex*) dm->data;
6220 
6221   PetscFunctionBegin;
6222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6223   if (cones) *cones = mesh->cones;
6224   PetscFunctionReturn(0);
6225 }
6226 
6227 #undef __FUNCT__
6228 #define __FUNCT__ "DMPlexGetConeOrientations"
6229 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6230 {
6231   DM_Plex *mesh = (DM_Plex*) dm->data;
6232 
6233   PetscFunctionBegin;
6234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6235   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6236   PetscFunctionReturn(0);
6237 }
6238 
6239 /******************************** FEM Support **********************************/
6240 
6241 #undef __FUNCT__
6242 #define __FUNCT__ "DMPlexVecGetClosure"
6243 /*@C
6244   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6245 
6246   Not collective
6247 
6248   Input Parameters:
6249 + dm - The DM
6250 . section - The section describing the layout in v, or NULL to use the default section
6251 . v - The local vector
6252 - point - The sieve point in the DM
6253 
6254   Output Parameters:
6255 + csize - The number of values in the closure, or NULL
6256 - values - The array of values, which is a borrowed array and should not be freed
6257 
6258   Fortran Notes:
6259   Since it returns an array, this routine is only available in Fortran 90, and you must
6260   include petsc.h90 in your code.
6261 
6262   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6263 
6264   Level: intermediate
6265 
6266 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6267 @*/
6268 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6269 {
6270   PetscScalar   *array, *vArray;
6271   PetscInt      *points = NULL;
6272   PetscInt       offsets[32];
6273   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6274   PetscErrorCode ierr;
6275 
6276   PetscFunctionBegin;
6277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6278   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6279   if (!section) {
6280     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6281   }
6282   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6283   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6284   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6285   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6286   /* Compress out points not in the section */
6287   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6288   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6289     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6290       points[q*2]   = points[p];
6291       points[q*2+1] = points[p+1];
6292       ++q;
6293     }
6294   }
6295   numPoints = q;
6296   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6297     PetscInt dof, fdof;
6298 
6299     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6300     for (f = 0; f < numFields; ++f) {
6301       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6302       offsets[f+1] += fdof;
6303     }
6304     size += dof;
6305   }
6306   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6307   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6308   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6309   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6310   for (p = 0; p < numPoints*2; p += 2) {
6311     PetscInt     o = points[p+1];
6312     PetscInt     dof, off, d;
6313     PetscScalar *varr;
6314 
6315     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6316     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6317     varr = &vArray[off];
6318     if (numFields) {
6319       PetscInt fdof, foff, fcomp, f, c;
6320 
6321       for (f = 0, foff = 0; f < numFields; ++f) {
6322         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6323         if (o >= 0) {
6324           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6325             array[offsets[f]] = varr[foff+d];
6326           }
6327         } else {
6328           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6329           for (d = fdof/fcomp-1; d >= 0; --d) {
6330             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6331               array[offsets[f]] = varr[foff+d*fcomp+c];
6332             }
6333           }
6334         }
6335         foff += fdof;
6336       }
6337     } else {
6338       if (o >= 0) {
6339         for (d = 0; d < dof; ++d, ++offsets[0]) {
6340           array[offsets[0]] = varr[d];
6341         }
6342       } else {
6343         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6344           array[offsets[0]] = varr[d];
6345         }
6346       }
6347     }
6348   }
6349   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6350   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6351   if (csize) *csize = size;
6352   *values = array;
6353   PetscFunctionReturn(0);
6354 }
6355 
6356 #undef __FUNCT__
6357 #define __FUNCT__ "DMPlexVecRestoreClosure"
6358 /*@C
6359   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6360 
6361   Not collective
6362 
6363   Input Parameters:
6364 + dm - The DM
6365 . section - The section describing the layout in v, or NULL to use the default section
6366 . v - The local vector
6367 . point - The sieve point in the DM
6368 . csize - The number of values in the closure, or NULL
6369 - values - The array of values, which is a borrowed array and should not be freed
6370 
6371   Fortran Notes:
6372   Since it returns an array, this routine is only available in Fortran 90, and you must
6373   include petsc.h90 in your code.
6374 
6375   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6376 
6377   Level: intermediate
6378 
6379 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6380 @*/
6381 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6382 {
6383   PetscInt       size = 0;
6384   PetscErrorCode ierr;
6385 
6386   PetscFunctionBegin;
6387   /* Should work without recalculating size */
6388   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6389   PetscFunctionReturn(0);
6390 }
6391 
6392 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6393 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6394 
6395 #undef __FUNCT__
6396 #define __FUNCT__ "updatePoint_private"
6397 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6398 {
6399   PetscInt        cdof;   /* The number of constraints on this point */
6400   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6401   PetscScalar    *a;
6402   PetscInt        off, cind = 0, k;
6403   PetscErrorCode  ierr;
6404 
6405   PetscFunctionBegin;
6406   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6407   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6408   a    = &array[off];
6409   if (!cdof || setBC) {
6410     if (orientation >= 0) {
6411       for (k = 0; k < dof; ++k) {
6412         fuse(&a[k], values[k]);
6413       }
6414     } else {
6415       for (k = 0; k < dof; ++k) {
6416         fuse(&a[k], values[dof-k-1]);
6417       }
6418     }
6419   } else {
6420     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6421     if (orientation >= 0) {
6422       for (k = 0; k < dof; ++k) {
6423         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6424         fuse(&a[k], values[k]);
6425       }
6426     } else {
6427       for (k = 0; k < dof; ++k) {
6428         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6429         fuse(&a[k], values[dof-k-1]);
6430       }
6431     }
6432   }
6433   PetscFunctionReturn(0);
6434 }
6435 
6436 #undef __FUNCT__
6437 #define __FUNCT__ "updatePointFields_private"
6438 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6439 {
6440   PetscScalar   *a;
6441   PetscInt       numFields, off, foff, f;
6442   PetscErrorCode ierr;
6443 
6444   PetscFunctionBegin;
6445   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6446   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6447   a    = &array[off];
6448   for (f = 0, foff = 0; f < numFields; ++f) {
6449     PetscInt        fdof, fcomp, fcdof;
6450     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6451     PetscInt        cind = 0, k, c;
6452 
6453     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6454     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6455     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6456     if (!fcdof || setBC) {
6457       if (orientation >= 0) {
6458         for (k = 0; k < fdof; ++k) {
6459           fuse(&a[foff+k], values[foffs[f]+k]);
6460         }
6461       } else {
6462         for (k = fdof/fcomp-1; k >= 0; --k) {
6463           for (c = 0; c < fcomp; ++c) {
6464             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6465           }
6466         }
6467       }
6468     } else {
6469       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6470       if (orientation >= 0) {
6471         for (k = 0; k < fdof; ++k) {
6472           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6473           fuse(&a[foff+k], values[foffs[f]+k]);
6474         }
6475       } else {
6476         for (k = fdof/fcomp-1; k >= 0; --k) {
6477           for (c = 0; c < fcomp; ++c) {
6478             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6479             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6480           }
6481         }
6482       }
6483     }
6484     foff     += fdof;
6485     foffs[f] += fdof;
6486   }
6487   PetscFunctionReturn(0);
6488 }
6489 
6490 #undef __FUNCT__
6491 #define __FUNCT__ "DMPlexVecSetClosure"
6492 /*@C
6493   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6494 
6495   Not collective
6496 
6497   Input Parameters:
6498 + dm - The DM
6499 . section - The section describing the layout in v, or NULL to use the default sectionw
6500 . v - The local vector
6501 . point - The sieve point in the DM
6502 . values - The array of values, which is a borrowed array and should not be freed
6503 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6504 
6505   Fortran Notes:
6506   Since it returns an array, this routine is only available in Fortran 90, and you must
6507   include petsc.h90 in your code.
6508 
6509   Level: intermediate
6510 
6511 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6512 @*/
6513 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6514 {
6515   PetscScalar   *array;
6516   PetscInt      *points = NULL;
6517   PetscInt       offsets[32];
6518   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6519   PetscErrorCode ierr;
6520 
6521   PetscFunctionBegin;
6522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6523   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6524   if (!section) {
6525     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6526   }
6527   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6528   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6529   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6530   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6531   /* Compress out points not in the section */
6532   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6533   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6534     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6535       points[q*2]   = points[p];
6536       points[q*2+1] = points[p+1];
6537       ++q;
6538     }
6539   }
6540   numPoints = q;
6541   for (p = 0; p < numPoints*2; p += 2) {
6542     PetscInt fdof;
6543 
6544     for (f = 0; f < numFields; ++f) {
6545       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6546       offsets[f+1] += fdof;
6547     }
6548   }
6549   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6550   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6551   if (numFields) {
6552     switch (mode) {
6553     case INSERT_VALUES:
6554       for (p = 0; p < numPoints*2; p += 2) {
6555         PetscInt o = points[p+1];
6556         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6557       } break;
6558     case INSERT_ALL_VALUES:
6559       for (p = 0; p < numPoints*2; p += 2) {
6560         PetscInt o = points[p+1];
6561         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6562       } break;
6563     case ADD_VALUES:
6564       for (p = 0; p < numPoints*2; p += 2) {
6565         PetscInt o = points[p+1];
6566         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6567       } break;
6568     case ADD_ALL_VALUES:
6569       for (p = 0; p < numPoints*2; p += 2) {
6570         PetscInt o = points[p+1];
6571         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6572       } break;
6573     default:
6574       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6575     }
6576   } else {
6577     switch (mode) {
6578     case INSERT_VALUES:
6579       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6580         PetscInt o = points[p+1];
6581         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6582         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6583       } break;
6584     case INSERT_ALL_VALUES:
6585       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6586         PetscInt o = points[p+1];
6587         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6588         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6589       } break;
6590     case ADD_VALUES:
6591       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6592         PetscInt o = points[p+1];
6593         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6594         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6595       } break;
6596     case ADD_ALL_VALUES:
6597       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6598         PetscInt o = points[p+1];
6599         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6600         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6601       } break;
6602     default:
6603       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6604     }
6605   }
6606   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6607   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6608   PetscFunctionReturn(0);
6609 }
6610 
6611 #undef __FUNCT__
6612 #define __FUNCT__ "DMPlexPrintMatSetValues"
6613 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6614 {
6615   PetscMPIInt    rank;
6616   PetscInt       i, j;
6617   PetscErrorCode ierr;
6618 
6619   PetscFunctionBegin;
6620   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
6621   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
6622   for (i = 0; i < numIndices; i++) {
6623     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
6624   }
6625   for (i = 0; i < numIndices; i++) {
6626     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
6627     for (j = 0; j < numIndices; j++) {
6628 #if defined(PETSC_USE_COMPLEX)
6629       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
6630 #else
6631       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
6632 #endif
6633     }
6634     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6635   }
6636   PetscFunctionReturn(0);
6637 }
6638 
6639 #undef __FUNCT__
6640 #define __FUNCT__ "indicesPoint_private"
6641 /* . off - The global offset of this point */
6642 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6643 {
6644   PetscInt        dof;    /* The number of unknowns on this point */
6645   PetscInt        cdof;   /* The number of constraints on this point */
6646   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6647   PetscInt        cind = 0, k;
6648   PetscErrorCode  ierr;
6649 
6650   PetscFunctionBegin;
6651   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6652   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6653   if (!cdof || setBC) {
6654     if (orientation >= 0) {
6655       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6656     } else {
6657       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6658     }
6659   } else {
6660     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6661     if (orientation >= 0) {
6662       for (k = 0; k < dof; ++k) {
6663         if ((cind < cdof) && (k == cdofs[cind])) {
6664           /* Insert check for returning constrained indices */
6665           indices[*loff+k] = -(off+k+1);
6666           ++cind;
6667         } else {
6668           indices[*loff+k] = off+k-cind;
6669         }
6670       }
6671     } else {
6672       for (k = 0; k < dof; ++k) {
6673         if ((cind < cdof) && (k == cdofs[cind])) {
6674           /* Insert check for returning constrained indices */
6675           indices[*loff+dof-k-1] = -(off+k+1);
6676           ++cind;
6677         } else {
6678           indices[*loff+dof-k-1] = off+k-cind;
6679         }
6680       }
6681     }
6682   }
6683   *loff += dof;
6684   PetscFunctionReturn(0);
6685 }
6686 
6687 #undef __FUNCT__
6688 #define __FUNCT__ "indicesPointFields_private"
6689 /* . off - The global offset of this point */
6690 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
6691 {
6692   PetscInt       numFields, foff, f;
6693   PetscErrorCode ierr;
6694 
6695   PetscFunctionBegin;
6696   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6697   for (f = 0, foff = 0; f < numFields; ++f) {
6698     PetscInt        fdof, fcomp, cfdof;
6699     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6700     PetscInt        cind = 0, k, c;
6701 
6702     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6703     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6704     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6705     if (!cfdof || setBC) {
6706       if (orientation >= 0) {
6707         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6708       } else {
6709         for (k = fdof/fcomp-1; k >= 0; --k) {
6710           for (c = 0; c < fcomp; ++c) {
6711             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6712           }
6713         }
6714       }
6715     } else {
6716       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6717       if (orientation >= 0) {
6718         for (k = 0; k < fdof; ++k) {
6719           if ((cind < cfdof) && (k == fcdofs[cind])) {
6720             indices[foffs[f]+k] = -(off+foff+k+1);
6721             ++cind;
6722           } else {
6723             indices[foffs[f]+k] = off+foff+k-cind;
6724           }
6725         }
6726       } else {
6727         for (k = fdof/fcomp-1; k >= 0; --k) {
6728           for (c = 0; c < fcomp; ++c) {
6729             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6730               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6731               ++cind;
6732             } else {
6733               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6734             }
6735           }
6736         }
6737       }
6738     }
6739     foff     += fdof - cfdof;
6740     foffs[f] += fdof;
6741   }
6742   PetscFunctionReturn(0);
6743 }
6744 
6745 #undef __FUNCT__
6746 #define __FUNCT__ "DMPlexMatSetClosure"
6747 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6748 {
6749   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6750   PetscInt      *points = NULL;
6751   PetscInt      *indices;
6752   PetscInt       offsets[32];
6753   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6754   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6755   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
6756   PetscErrorCode ierr;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
6761   if (useDefault) {
6762     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6763   }
6764   if (useGlobalDefault) {
6765     if (useDefault) {
6766       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
6767     } else {
6768       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6769     }
6770   }
6771   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6772   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6773   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6774   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6775   /* Compress out points not in the section */
6776   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6777   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6778     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6779       points[q*2]   = points[p];
6780       points[q*2+1] = points[p+1];
6781       ++q;
6782     }
6783   }
6784   numPoints = q;
6785   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6786     PetscInt fdof;
6787 
6788     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6789     for (f = 0; f < numFields; ++f) {
6790       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6791       offsets[f+1] += fdof;
6792     }
6793     numIndices += dof;
6794   }
6795   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6796 
6797   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
6798   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6799   if (numFields) {
6800     for (p = 0; p < numPoints*2; p += 2) {
6801       PetscInt o = points[p+1];
6802       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6803       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
6804     }
6805   } else {
6806     for (p = 0, off = 0; p < numPoints*2; p += 2) {
6807       PetscInt o = points[p+1];
6808       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6809       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
6810     }
6811   }
6812   if (useGlobalDefault && !useDefault) {
6813     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6814   }
6815   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
6816   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6817   if (ierr) {
6818     PetscMPIInt    rank;
6819     PetscErrorCode ierr2;
6820 
6821     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6822     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6823     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
6824     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
6825     CHKERRQ(ierr);
6826   }
6827   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6828   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6829   PetscFunctionReturn(0);
6830 }
6831 
6832 #undef __FUNCT__
6833 #define __FUNCT__ "DMPlexGetHybridBounds"
6834 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6835 {
6836   DM_Plex       *mesh = (DM_Plex*) dm->data;
6837   PetscInt       dim;
6838   PetscErrorCode ierr;
6839 
6840   PetscFunctionBegin;
6841   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6842   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6843   if (cMax) *cMax = mesh->hybridPointMax[dim];
6844   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6845   if (eMax) *eMax = mesh->hybridPointMax[1];
6846   if (vMax) *vMax = mesh->hybridPointMax[0];
6847   PetscFunctionReturn(0);
6848 }
6849 
6850 #undef __FUNCT__
6851 #define __FUNCT__ "DMPlexSetHybridBounds"
6852 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6853 {
6854   DM_Plex       *mesh = (DM_Plex*) dm->data;
6855   PetscInt       dim;
6856   PetscErrorCode ierr;
6857 
6858   PetscFunctionBegin;
6859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6860   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6861   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6862   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6863   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6864   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6865   PetscFunctionReturn(0);
6866 }
6867 
6868 #undef __FUNCT__
6869 #define __FUNCT__ "DMPlexGetVTKCellHeight"
6870 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6871 {
6872   DM_Plex *mesh = (DM_Plex*) dm->data;
6873 
6874   PetscFunctionBegin;
6875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6876   PetscValidPointer(cellHeight, 2);
6877   *cellHeight = mesh->vtkCellHeight;
6878   PetscFunctionReturn(0);
6879 }
6880 
6881 #undef __FUNCT__
6882 #define __FUNCT__ "DMPlexSetVTKCellHeight"
6883 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6884 {
6885   DM_Plex *mesh = (DM_Plex*) dm->data;
6886 
6887   PetscFunctionBegin;
6888   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6889   mesh->vtkCellHeight = cellHeight;
6890   PetscFunctionReturn(0);
6891 }
6892 
6893 #undef __FUNCT__
6894 #define __FUNCT__ "DMPlexCreateNumbering_Private"
6895 /* We can easily have a form that takes an IS instead */
6896 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
6897 {
6898   PetscSection   section, globalSection;
6899   PetscInt      *numbers, p;
6900   PetscErrorCode ierr;
6901 
6902   PetscFunctionBegin;
6903   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6904   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6905   for (p = pStart; p < pEnd; ++p) {
6906     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6907   }
6908   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6909   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6910   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
6911   for (p = pStart; p < pEnd; ++p) {
6912     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6913   }
6914   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6915   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6916   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6917   PetscFunctionReturn(0);
6918 }
6919 
6920 #undef __FUNCT__
6921 #define __FUNCT__ "DMPlexGetCellNumbering"
6922 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6923 {
6924   DM_Plex       *mesh = (DM_Plex*) dm->data;
6925   PetscInt       cellHeight, cStart, cEnd, cMax;
6926   PetscErrorCode ierr;
6927 
6928   PetscFunctionBegin;
6929   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6930   if (!mesh->globalCellNumbers) {
6931     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6932     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6933     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6934     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
6935     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
6936   }
6937   *globalCellNumbers = mesh->globalCellNumbers;
6938   PetscFunctionReturn(0);
6939 }
6940 
6941 #undef __FUNCT__
6942 #define __FUNCT__ "DMPlexGetVertexNumbering"
6943 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6944 {
6945   DM_Plex       *mesh = (DM_Plex*) dm->data;
6946   PetscInt       vStart, vEnd, vMax;
6947   PetscErrorCode ierr;
6948 
6949   PetscFunctionBegin;
6950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6951   if (!mesh->globalVertexNumbers) {
6952     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6953     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6954     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
6955     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
6956   }
6957   *globalVertexNumbers = mesh->globalVertexNumbers;
6958   PetscFunctionReturn(0);
6959 }
6960 
6961 
6962 #undef __FUNCT__
6963 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
6964 /*@C
6965   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
6966   the local section and an SF describing the section point overlap.
6967 
6968   Input Parameters:
6969   + s - The PetscSection for the local field layout
6970   . sf - The SF describing parallel layout of the section points
6971   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
6972   . label - The label specifying the points
6973   - labelValue - The label stratum specifying the points
6974 
6975   Output Parameter:
6976   . gsection - The PetscSection for the global field layout
6977 
6978   Note: This gives negative sizes and offsets to points not owned by this process
6979 
6980   Level: developer
6981 
6982 .seealso: PetscSectionCreate()
6983 @*/
6984 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
6985 {
6986   PetscInt      *neg;
6987   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
6988   PetscErrorCode ierr;
6989 
6990   PetscFunctionBegin;
6991   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
6992   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
6993   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
6994   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
6995   /* Mark ghost points with negative dof */
6996   for (p = pStart; p < pEnd; ++p) {
6997     PetscInt value;
6998 
6999     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7000     if (value != labelValue) continue;
7001     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7002     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7003     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7004     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7005     neg[p-pStart] = -(dof+1);
7006   }
7007   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7008   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7009   if (nroots >= 0) {
7010     if (nroots > pEnd - pStart) {
7011       PetscInt *tmpDof;
7012       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7013       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
7014       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7015       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7016       for (p = pStart; p < pEnd; ++p) {
7017         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7018       }
7019       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
7020     } else {
7021       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7022       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7023     }
7024   }
7025   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7026   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7027     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7028 
7029     (*gsection)->atlasOff[p] = off;
7030 
7031     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7032   }
7033   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7034   globalOff -= off;
7035   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7036     (*gsection)->atlasOff[p] += globalOff;
7037 
7038     neg[p] = -((*gsection)->atlasOff[p]+1);
7039   }
7040   /* Put in negative offsets for ghost points */
7041   if (nroots >= 0) {
7042     if (nroots > pEnd - pStart) {
7043       PetscInt *tmpOff;
7044       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7045       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7046       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7047       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7048       for (p = pStart; p < pEnd; ++p) {
7049         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7050       }
7051       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
7052     } else {
7053       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7054       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7055     }
7056   }
7057   ierr = PetscFree(neg);CHKERRQ(ierr);
7058   PetscFunctionReturn(0);
7059 }
7060