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