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