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