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