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