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