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