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