xref: /petsc/src/dm/impls/plex/plex.c (revision 9895aa37ac365bac650f6bd8bf977519f7222510) !
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 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     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "DMView_Plex"
320 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
321 {
322   PetscBool      iascii, isbinary;
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
327   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
330   if (iascii) {
331     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
332 #if 0
333   } else if (isbinary) {
334     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
335 #endif
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "DMDestroy_Plex"
342 PetscErrorCode DMDestroy_Plex(DM dm)
343 {
344   DM_Plex       *mesh = (DM_Plex*) dm->data;
345   DMLabel        next  = mesh->labels;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   if (--mesh->refct > 0) PetscFunctionReturn(0);
350   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
353   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
355   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
356   while (next) {
357     DMLabel tmp = next->next;
358 
359     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
360     next = tmp;
361   }
362   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
364   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
365   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
366   ierr = PetscFree(mesh);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
372 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
373 {
374   const PetscInt *support = NULL;
375   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
376   PetscErrorCode  ierr;
377 
378   PetscFunctionBegin;
379   if (useClosure) {
380     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
381     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
382     for (s = 0; s < supportSize; ++s) {
383       const PetscInt *cone = NULL;
384       PetscInt        coneSize, c, q;
385 
386       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
387       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
388       for (c = 0; c < coneSize; ++c) {
389         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
390           if (cone[c] == adj[q]) break;
391         }
392         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
393       }
394     }
395   } else {
396     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
397     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
398     for (s = 0; s < supportSize; ++s) {
399       const PetscInt *cone = NULL;
400       PetscInt        coneSize, c, q;
401 
402       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
403       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
404       for (c = 0; c < coneSize; ++c) {
405         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
406           if (cone[c] == adj[q]) break;
407         }
408         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
409       }
410     }
411   }
412   *adjSize = numAdj;
413   PetscFunctionReturn(0);
414 }
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "DMPlexGetAdjacency_Private"
418 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
419 {
420   const PetscInt *star  = tmpClosure;
421   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
422   PetscErrorCode  ierr;
423 
424   PetscFunctionBegin;
425   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
426   for (s = 2; s < starSize*2; s += 2) {
427     const PetscInt *closure = NULL;
428     PetscInt        closureSize, c, q;
429 
430     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
431     for (c = 0; c < closureSize*2; c += 2) {
432       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
433         if (closure[c] == adj[q]) break;
434       }
435       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
436     }
437     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
438   }
439   *adjSize = numAdj;
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
445 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
446 {
447   DM_Plex *mesh = (DM_Plex*) dm->data;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451   mesh->preallocCenterDim = preallocCenterDim;
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "DMPlexPreallocateOperator"
457 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
458 {
459   DM_Plex           *mesh = (DM_Plex*) dm->data;
460   MPI_Comm           comm;
461   PetscSF            sf, sfDof, sfAdj;
462   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
463   PetscInt           nleaves, l, p;
464   const PetscInt    *leaves;
465   const PetscSFNode *remotes;
466   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
467   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
468   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
469   PetscLayout        rLayout;
470   PetscInt           locRows, rStart, rEnd, r;
471   PetscMPIInt        size;
472   PetscBool          useClosure, debug = PETSC_FALSE;
473   PetscErrorCode     ierr;
474 
475   PetscFunctionBegin;
476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
477   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
478   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
481   /* Create dof SF based on point SF */
482   if (debug) {
483     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
487     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
488     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
489   }
490   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
491   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
492   if (debug) {
493     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
494     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
495   }
496   /* Create section for dof adjacency (dof ==> # adj dof) */
497   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
498   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
499   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
500   if (mesh->preallocCenterDim == dim) {
501     useClosure = PETSC_FALSE;
502   } else if (mesh->preallocCenterDim == 0) {
503     useClosure = PETSC_TRUE;
504   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
505 
506   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
507   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
510   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
511   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
512   /*   Fill in the ghost dofs on the interface */
513   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
514   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
515   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
516 
517   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
518   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
519 
520   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
521 
522   /*
523    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
524     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
525        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
526     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
527        Create sfAdj connecting rootSectionAdj and leafSectionAdj
528     3. Visit unowned points on interface, write adjacencies to adj
529        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
530     4. Visit owned points on interface, write adjacencies to rootAdj
531        Remove redundancy in rootAdj
532    ** The last two traversals use transitive closure
533     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
534        Allocate memory addressed by sectionAdj (cols)
535     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
536    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
537   */
538 
539   for (l = 0; l < nleaves; ++l) {
540     PetscInt dof, off, d, q;
541     PetscInt p = leaves[l], numAdj = maxAdjSize;
542 
543     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
544     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
545     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
546     for (q = 0; q < numAdj; ++q) {
547       PetscInt ndof, ncdof;
548 
549       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
550       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
551       for (d = off; d < off+dof; ++d) {
552         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
553       }
554     }
555   }
556   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
557   if (debug) {
558     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
559     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
560   }
561   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
562   if (size > 1) {
563     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
564     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
565   }
566   if (debug) {
567     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
568     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
569   }
570   /* Add in local adjacency sizes for owned dofs on interface (roots) */
571   for (p = pStart; p < pEnd; ++p) {
572     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
573 
574     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
575     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
576     if (!dof) continue;
577     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
578     if (adof <= 0) continue;
579     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
580     for (q = 0; q < numAdj; ++q) {
581       PetscInt ndof, ncdof;
582 
583       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
584       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
585       for (d = off; d < off+dof; ++d) {
586         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
587       }
588     }
589   }
590   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
591   if (debug) {
592     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
593     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
594   }
595   /* Create adj SF based on dof SF */
596   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
597   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
598   if (debug) {
599     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
600     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
601   }
602   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
603   /* Create leaf adjacency */
604   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
605   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
606   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
607   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
608   for (l = 0; l < nleaves; ++l) {
609     PetscInt dof, off, d, q;
610     PetscInt p = leaves[l], numAdj = maxAdjSize;
611 
612     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
613     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
614     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
615     for (d = off; d < off+dof; ++d) {
616       PetscInt aoff, i = 0;
617 
618       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
619       for (q = 0; q < numAdj; ++q) {
620         PetscInt ndof, ncdof, ngoff, nd;
621 
622         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
623         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
624         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
625         for (nd = 0; nd < ndof-ncdof; ++nd) {
626           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
627           ++i;
628         }
629       }
630     }
631   }
632   /* Debugging */
633   if (debug) {
634     IS tmp;
635     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
636     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
637     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
638   }
639   /* Gather adjacenct indices to root */
640   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
641   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
642   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
643   if (size > 1) {
644     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
645     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
646   }
647   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
648   ierr = PetscFree(adj);CHKERRQ(ierr);
649   /* Debugging */
650   if (debug) {
651     IS tmp;
652     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
653     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
654     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
655   }
656   /* Add in local adjacency indices for owned dofs on interface (roots) */
657   for (p = pStart; p < pEnd; ++p) {
658     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
659 
660     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
661     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
662     if (!dof) continue;
663     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
664     if (adof <= 0) continue;
665     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
666     for (d = off; d < off+dof; ++d) {
667       PetscInt adof, aoff, i;
668 
669       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
670       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
671       i    = adof-1;
672       for (q = 0; q < numAdj; ++q) {
673         PetscInt ndof, ncdof, ngoff, nd;
674 
675         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
676         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
677         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
678         for (nd = 0; nd < ndof-ncdof; ++nd) {
679           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
680           --i;
681         }
682       }
683     }
684   }
685   /* Debugging */
686   if (debug) {
687     IS tmp;
688     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
689     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
690     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
691   }
692   /* Compress indices */
693   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
694   for (p = pStart; p < pEnd; ++p) {
695     PetscInt dof, cdof, off, d;
696     PetscInt adof, aoff;
697 
698     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
699     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
700     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
701     if (!dof) continue;
702     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
703     if (adof <= 0) continue;
704     for (d = off; d < off+dof-cdof; ++d) {
705       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
706       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
707       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
708       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
709     }
710   }
711   /* Debugging */
712   if (debug) {
713     IS tmp;
714     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
715     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
716     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
717     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
718     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
719   }
720   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
721   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
722   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
723   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
724   for (p = pStart; p < pEnd; ++p) {
725     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
726     PetscBool found  = PETSC_TRUE;
727 
728     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
729     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
730     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
731     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
732     for (d = 0; d < dof-cdof; ++d) {
733       PetscInt ldof, rdof;
734 
735       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
736       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
737       if (ldof > 0) {
738         /* We do not own this point */
739       } else if (rdof > 0) {
740         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
741       } else {
742         found = PETSC_FALSE;
743       }
744     }
745     if (found) continue;
746     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
747     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
748     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
749     for (q = 0; q < numAdj; ++q) {
750       PetscInt ndof, ncdof, noff;
751 
752       /* Adjacent points may not be in the section chart */
753       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
754       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
755       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
756       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
757       for (d = goff; d < goff+dof-cdof; ++d) {
758         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
759       }
760     }
761   }
762   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
763   if (debug) {
764     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
765     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
766   }
767   /* Get adjacent indices */
768   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
769   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
770   for (p = pStart; p < pEnd; ++p) {
771     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
772     PetscBool found  = PETSC_TRUE;
773 
774     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
775     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
776     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
777     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
778     for (d = 0; d < dof-cdof; ++d) {
779       PetscInt ldof, rdof;
780 
781       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
782       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
783       if (ldof > 0) {
784         /* We do not own this point */
785       } else if (rdof > 0) {
786         PetscInt aoff, roff;
787 
788         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
789         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
790         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
791       } else {
792         found = PETSC_FALSE;
793       }
794     }
795     if (found) continue;
796     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
797     for (d = goff; d < goff+dof-cdof; ++d) {
798       PetscInt adof, aoff, i = 0;
799 
800       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
801       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
802       for (q = 0; q < numAdj; ++q) {
803         PetscInt        ndof, ncdof, ngoff, nd;
804         const PetscInt *ncind;
805 
806         /* Adjacent points may not be in the section chart */
807         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
808         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
809         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
810         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
811         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
812         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
813           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
814         }
815       }
816       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
817     }
818   }
819   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
820   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
821   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
822   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
823   /* Debugging */
824   if (debug) {
825     IS tmp;
826     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
827     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
828     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
829   }
830   /* Create allocation vectors from adjacency graph */
831   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
832   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
833   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
834   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
835   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
836   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
837   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
838   /* Only loop over blocks of rows */
839   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
840   for (r = rStart/bs; r < rEnd/bs; ++r) {
841     const PetscInt row = r*bs;
842     PetscInt       numCols, cStart, c;
843 
844     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
845     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
846     for (c = cStart; c < cStart+numCols; ++c) {
847       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
848         ++dnz[r-rStart];
849         if (cols[c] >= row) ++dnzu[r-rStart];
850       } else {
851         ++onz[r-rStart];
852         if (cols[c] >= row) ++onzu[r-rStart];
853       }
854     }
855   }
856   if (bs > 1) {
857     for (r = 0; r < locRows/bs; ++r) {
858       dnz[r]  /= bs;
859       onz[r]  /= bs;
860       dnzu[r] /= bs;
861       onzu[r] /= bs;
862     }
863   }
864   /* Set matrix pattern */
865   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
866   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
867   /* Fill matrix with zeros */
868   if (fillMatrix) {
869     PetscScalar *values;
870     PetscInt     maxRowLen = 0;
871 
872     for (r = rStart; r < rEnd; ++r) {
873       PetscInt len;
874 
875       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
876       maxRowLen = PetscMax(maxRowLen, len);
877     }
878     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
879     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
880     for (r = rStart; r < rEnd; ++r) {
881       PetscInt numCols, cStart;
882 
883       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
884       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
885       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
886     }
887     ierr = PetscFree(values);CHKERRQ(ierr);
888     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
889     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
890   }
891   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
892   ierr = PetscFree(cols);CHKERRQ(ierr);
893   PetscFunctionReturn(0);
894 }
895 
896 #if 0
897 #undef __FUNCT__
898 #define __FUNCT__ "DMPlexPreallocateOperator_2"
899 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
900 {
901   PetscInt       *tmpClosure,*tmpAdj,*visits;
902   PetscInt        c,cStart,cEnd,pStart,pEnd;
903   PetscErrorCode  ierr;
904 
905   PetscFunctionBegin;
906   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
907   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
908   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
909 
910   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
911 
912   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
913   npoints = pEnd - pStart;
914 
915   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
916   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
917   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
918   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
919   for (c=cStart; c<cEnd; c++) {
920     PetscInt *support = tmpClosure;
921     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
922     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
923   }
924   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
925   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
926   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
927   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
928 
929   ierr = PetscSFGetRanks();CHKERRQ(ierr);
930 
931 
932   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
933   for (c=cStart; c<cEnd; c++) {
934     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
935     /*
936      Depth-first walk of transitive closure.
937      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
938      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
939      */
940   }
941 
942   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
943   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
944   PetscFunctionReturn(0);
945 }
946 #endif
947 
948 #undef __FUNCT__
949 #define __FUNCT__ "DMCreateMatrix_Plex"
950 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
951 {
952   PetscSection   section, sectionGlobal;
953   PetscInt       bs = -1;
954   PetscInt       localSize;
955   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
956   PetscErrorCode ierr;
957 
958   PetscFunctionBegin;
959 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
960   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
961 #endif
962   if (!mtype) mtype = MATAIJ;
963   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
964   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
965   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
966   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
967   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
968   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
969   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
970   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
975   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
976   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
977   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
978   /* Check for symmetric storage */
979   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
980   if (isSymmetric) {
981     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
982   }
983   if (!isShell) {
984     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
985     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
986 
987     if (bs < 0) {
988       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
989         PetscInt pStart, pEnd, p, dof, cdof;
990 
991         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
992         for (p = pStart; p < pEnd; ++p) {
993           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
994           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
995           if (dof-cdof) {
996             if (bs < 0) {
997               bs = dof-cdof;
998             } else if (bs != dof-cdof) {
999               /* Layout does not admit a pointwise block size */
1000               bs = 1;
1001               break;
1002             }
1003           }
1004         }
1005         /* Must have same blocksize on all procs (some might have no points) */
1006         bsLocal = bs;
1007         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1008         bsLocal = bs < 0 ? bsMax : bs;
1009         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1010         if (bsMin != bsMax) {
1011           bs = 1;
1012         } else {
1013           bs = bsMax;
1014         }
1015       } else {
1016         bs = 1;
1017       }
1018     }
1019     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1020     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1021     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1022     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1023     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1024     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1025     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1026   }
1027   PetscFunctionReturn(0);
1028 }
1029 
1030 #undef __FUNCT__
1031 #define __FUNCT__ "DMPlexGetDimension"
1032 /*@
1033   DMPlexGetDimension - Return the topological mesh dimension
1034 
1035   Not collective
1036 
1037   Input Parameter:
1038 . mesh - The DMPlex
1039 
1040   Output Parameter:
1041 . dim - The topological mesh dimension
1042 
1043   Level: beginner
1044 
1045 .seealso: DMPlexCreate()
1046 @*/
1047 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1048 {
1049   DM_Plex *mesh = (DM_Plex*) dm->data;
1050 
1051   PetscFunctionBegin;
1052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1053   PetscValidPointer(dim, 2);
1054   *dim = mesh->dim;
1055   PetscFunctionReturn(0);
1056 }
1057 
1058 #undef __FUNCT__
1059 #define __FUNCT__ "DMPlexSetDimension"
1060 /*@
1061   DMPlexSetDimension - Set the topological mesh dimension
1062 
1063   Collective on mesh
1064 
1065   Input Parameters:
1066 + mesh - The DMPlex
1067 - dim - The topological mesh dimension
1068 
1069   Level: beginner
1070 
1071 .seealso: DMPlexCreate()
1072 @*/
1073 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1074 {
1075   DM_Plex *mesh = (DM_Plex*) dm->data;
1076 
1077   PetscFunctionBegin;
1078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1079   PetscValidLogicalCollectiveInt(dm, dim, 2);
1080   mesh->dim               = dim;
1081   mesh->preallocCenterDim = dim;
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 #undef __FUNCT__
1086 #define __FUNCT__ "DMPlexGetChart"
1087 /*@
1088   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1089 
1090   Not collective
1091 
1092   Input Parameter:
1093 . mesh - The DMPlex
1094 
1095   Output Parameters:
1096 + pStart - The first mesh point
1097 - pEnd   - The upper bound for mesh points
1098 
1099   Level: beginner
1100 
1101 .seealso: DMPlexCreate(), DMPlexSetChart()
1102 @*/
1103 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1104 {
1105   DM_Plex       *mesh = (DM_Plex*) dm->data;
1106   PetscErrorCode ierr;
1107 
1108   PetscFunctionBegin;
1109   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1110   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 #undef __FUNCT__
1115 #define __FUNCT__ "DMPlexSetChart"
1116 /*@
1117   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1118 
1119   Not collective
1120 
1121   Input Parameters:
1122 + mesh - The DMPlex
1123 . pStart - The first mesh point
1124 - pEnd   - The upper bound for mesh points
1125 
1126   Output Parameters:
1127 
1128   Level: beginner
1129 
1130 .seealso: DMPlexCreate(), DMPlexGetChart()
1131 @*/
1132 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1133 {
1134   DM_Plex       *mesh = (DM_Plex*) dm->data;
1135   PetscErrorCode ierr;
1136 
1137   PetscFunctionBegin;
1138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1139   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1140   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1141   PetscFunctionReturn(0);
1142 }
1143 
1144 #undef __FUNCT__
1145 #define __FUNCT__ "DMPlexGetConeSize"
1146 /*@
1147   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1148 
1149   Not collective
1150 
1151   Input Parameters:
1152 + mesh - The DMPlex
1153 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1154 
1155   Output Parameter:
1156 . size - The cone size for point p
1157 
1158   Level: beginner
1159 
1160 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1161 @*/
1162 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1163 {
1164   DM_Plex       *mesh = (DM_Plex*) dm->data;
1165   PetscErrorCode ierr;
1166 
1167   PetscFunctionBegin;
1168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1169   PetscValidPointer(size, 3);
1170   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 #undef __FUNCT__
1175 #define __FUNCT__ "DMPlexSetConeSize"
1176 /*@
1177   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1178 
1179   Not collective
1180 
1181   Input Parameters:
1182 + mesh - The DMPlex
1183 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1184 - size - The cone size for point p
1185 
1186   Output Parameter:
1187 
1188   Note:
1189   This should be called after DMPlexSetChart().
1190 
1191   Level: beginner
1192 
1193 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1194 @*/
1195 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1196 {
1197   DM_Plex       *mesh = (DM_Plex*) dm->data;
1198   PetscErrorCode ierr;
1199 
1200   PetscFunctionBegin;
1201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1202   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1203 
1204   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1205   PetscFunctionReturn(0);
1206 }
1207 
1208 #undef __FUNCT__
1209 #define __FUNCT__ "DMPlexGetCone"
1210 /*@C
1211   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1212 
1213   Not collective
1214 
1215   Input Parameters:
1216 + mesh - The DMPlex
1217 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1218 
1219   Output Parameter:
1220 . cone - An array of points which are on the in-edges for point p
1221 
1222   Level: beginner
1223 
1224   Note:
1225   This routine is not available in Fortran.
1226 
1227 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1228 @*/
1229 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1230 {
1231   DM_Plex       *mesh = (DM_Plex*) dm->data;
1232   PetscInt       off;
1233   PetscErrorCode ierr;
1234 
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1237   PetscValidPointer(cone, 3);
1238   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1239   *cone = &mesh->cones[off];
1240   PetscFunctionReturn(0);
1241 }
1242 
1243 #undef __FUNCT__
1244 #define __FUNCT__ "DMPlexSetCone"
1245 /*@
1246   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1247 
1248   Not collective
1249 
1250   Input Parameters:
1251 + mesh - The DMPlex
1252 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1253 - cone - An array of points which are on the in-edges for point p
1254 
1255   Output Parameter:
1256 
1257   Note:
1258   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1259 
1260   Level: beginner
1261 
1262 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1263 @*/
1264 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1265 {
1266   DM_Plex       *mesh = (DM_Plex*) dm->data;
1267   PetscInt       pStart, pEnd;
1268   PetscInt       dof, off, c;
1269   PetscErrorCode ierr;
1270 
1271   PetscFunctionBegin;
1272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1273   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1274   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1275   if (dof) PetscValidPointer(cone, 3);
1276   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1277   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);
1278   for (c = 0; c < dof; ++c) {
1279     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);
1280     mesh->cones[off+c] = cone[c];
1281   }
1282   PetscFunctionReturn(0);
1283 }
1284 
1285 #undef __FUNCT__
1286 #define __FUNCT__ "DMPlexGetConeOrientation"
1287 /*@C
1288   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1289 
1290   Not collective
1291 
1292   Input Parameters:
1293 + mesh - The DMPlex
1294 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1295 
1296   Output Parameter:
1297 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1298                     integer giving the prescription for cone traversal. If it is negative, the cone is
1299                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1300                     the index of the cone point on which to start.
1301 
1302   Level: beginner
1303 
1304   Note:
1305   This routine is not available in Fortran.
1306 
1307 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1308 @*/
1309 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1310 {
1311   DM_Plex       *mesh = (DM_Plex*) dm->data;
1312   PetscInt       off;
1313   PetscErrorCode ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1317 #if defined(PETSC_USE_DEBUG)
1318   {
1319     PetscInt dof;
1320     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1321     if (dof) PetscValidPointer(coneOrientation, 3);
1322   }
1323 #endif
1324   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1325 
1326   *coneOrientation = &mesh->coneOrientations[off];
1327   PetscFunctionReturn(0);
1328 }
1329 
1330 #undef __FUNCT__
1331 #define __FUNCT__ "DMPlexSetConeOrientation"
1332 /*@
1333   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1334 
1335   Not collective
1336 
1337   Input Parameters:
1338 + mesh - The DMPlex
1339 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1340 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1341                     integer giving the prescription for cone traversal. If it is negative, the cone is
1342                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1343                     the index of the cone point on which to start.
1344 
1345   Output Parameter:
1346 
1347   Note:
1348   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1349 
1350   Level: beginner
1351 
1352 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1353 @*/
1354 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1355 {
1356   DM_Plex       *mesh = (DM_Plex*) dm->data;
1357   PetscInt       pStart, pEnd;
1358   PetscInt       dof, off, c;
1359   PetscErrorCode ierr;
1360 
1361   PetscFunctionBegin;
1362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1363   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1364   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1365   if (dof) PetscValidPointer(coneOrientation, 3);
1366   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1367   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);
1368   for (c = 0; c < dof; ++c) {
1369     PetscInt cdof, o = coneOrientation[c];
1370 
1371     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1372     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);
1373     mesh->coneOrientations[off+c] = o;
1374   }
1375   PetscFunctionReturn(0);
1376 }
1377 
1378 #undef __FUNCT__
1379 #define __FUNCT__ "DMPlexInsertCone"
1380 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1381 {
1382   DM_Plex       *mesh = (DM_Plex*) dm->data;
1383   PetscInt       pStart, pEnd;
1384   PetscInt       dof, off;
1385   PetscErrorCode ierr;
1386 
1387   PetscFunctionBegin;
1388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1389   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1390   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1391   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1392   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);
1393   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);
1394   if (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);
1395   mesh->cones[off+conePos] = conePoint;
1396   PetscFunctionReturn(0);
1397 }
1398 
1399 #undef __FUNCT__
1400 #define __FUNCT__ "DMPlexGetSupportSize"
1401 /*@
1402   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1403 
1404   Not collective
1405 
1406   Input Parameters:
1407 + mesh - The DMPlex
1408 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1409 
1410   Output Parameter:
1411 . size - The support size for point p
1412 
1413   Level: beginner
1414 
1415 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1416 @*/
1417 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1418 {
1419   DM_Plex       *mesh = (DM_Plex*) dm->data;
1420   PetscErrorCode ierr;
1421 
1422   PetscFunctionBegin;
1423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1424   PetscValidPointer(size, 3);
1425   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 #undef __FUNCT__
1430 #define __FUNCT__ "DMPlexSetSupportSize"
1431 /*@
1432   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1433 
1434   Not collective
1435 
1436   Input Parameters:
1437 + mesh - The DMPlex
1438 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1439 - size - The support size for point p
1440 
1441   Output Parameter:
1442 
1443   Note:
1444   This should be called after DMPlexSetChart().
1445 
1446   Level: beginner
1447 
1448 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1449 @*/
1450 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1451 {
1452   DM_Plex       *mesh = (DM_Plex*) dm->data;
1453   PetscErrorCode ierr;
1454 
1455   PetscFunctionBegin;
1456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1457   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1458 
1459   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 #undef __FUNCT__
1464 #define __FUNCT__ "DMPlexGetSupport"
1465 /*@C
1466   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1467 
1468   Not collective
1469 
1470   Input Parameters:
1471 + mesh - The DMPlex
1472 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1473 
1474   Output Parameter:
1475 . support - An array of points which are on the out-edges for point p
1476 
1477   Level: beginner
1478 
1479 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1480 @*/
1481 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1482 {
1483   DM_Plex       *mesh = (DM_Plex*) dm->data;
1484   PetscInt       off;
1485   PetscErrorCode ierr;
1486 
1487   PetscFunctionBegin;
1488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1489   PetscValidPointer(support, 3);
1490   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1491   *support = &mesh->supports[off];
1492   PetscFunctionReturn(0);
1493 }
1494 
1495 #undef __FUNCT__
1496 #define __FUNCT__ "DMPlexSetSupport"
1497 /*@
1498   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1499 
1500   Not collective
1501 
1502   Input Parameters:
1503 + mesh - The DMPlex
1504 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1505 - support - An array of points which are on the in-edges for point p
1506 
1507   Output Parameter:
1508 
1509   Note:
1510   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1511 
1512   Level: beginner
1513 
1514 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1515 @*/
1516 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1517 {
1518   DM_Plex       *mesh = (DM_Plex*) dm->data;
1519   PetscInt       pStart, pEnd;
1520   PetscInt       dof, off, c;
1521   PetscErrorCode ierr;
1522 
1523   PetscFunctionBegin;
1524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1525   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1526   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1527   if (dof) PetscValidPointer(support, 3);
1528   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1529   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);
1530   for (c = 0; c < dof; ++c) {
1531     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);
1532     mesh->supports[off+c] = support[c];
1533   }
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "DMPlexInsertSupport"
1539 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1540 {
1541   DM_Plex       *mesh = (DM_Plex*) dm->data;
1542   PetscInt       pStart, pEnd;
1543   PetscInt       dof, off;
1544   PetscErrorCode ierr;
1545 
1546   PetscFunctionBegin;
1547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1548   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1549   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1550   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1551   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);
1552   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);
1553   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);
1554   mesh->supports[off+supportPos] = supportPoint;
1555   PetscFunctionReturn(0);
1556 }
1557 
1558 #undef __FUNCT__
1559 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1560 /*@C
1561   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1562 
1563   Not collective
1564 
1565   Input Parameters:
1566 + mesh - The DMPlex
1567 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1568 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1569 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1570 
1571   Output Parameters:
1572 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1573 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1574 
1575   Note:
1576   If using internal storage (points is NULL on input), each call overwrites the last output.
1577 
1578   Level: beginner
1579 
1580 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1581 @*/
1582 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1583 {
1584   DM_Plex        *mesh = (DM_Plex*) dm->data;
1585   PetscInt       *closure, *fifo;
1586   const PetscInt *tmp = NULL, *tmpO = NULL;
1587   PetscInt        tmpSize, t;
1588   PetscInt        depth       = 0, maxSize;
1589   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1590   PetscErrorCode  ierr;
1591 
1592   PetscFunctionBegin;
1593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1594   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1595   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1596   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1597   if (*points) {
1598     closure = *points;
1599   } else {
1600     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1601   }
1602   closure[0] = p; closure[1] = 0;
1603   /* This is only 1-level */
1604   if (useCone) {
1605     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1606     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1607     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1608   } else {
1609     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1610     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1611   }
1612   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1613     const PetscInt cp = tmp[t];
1614     const PetscInt co = tmpO ? tmpO[t] : 0;
1615 
1616     closure[closureSize]   = cp;
1617     closure[closureSize+1] = co;
1618     fifo[fifoSize]         = cp;
1619     fifo[fifoSize+1]       = co;
1620   }
1621   while (fifoSize - fifoStart) {
1622     const PetscInt q   = fifo[fifoStart];
1623     const PetscInt o   = fifo[fifoStart+1];
1624     const PetscInt rev = o >= 0 ? 0 : 1;
1625     const PetscInt off = rev ? -(o+1) : o;
1626 
1627     if (useCone) {
1628       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1629       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1630       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1631     } else {
1632       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1633       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1634       tmpO = NULL;
1635     }
1636     for (t = 0; t < tmpSize; ++t) {
1637       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1638       const PetscInt cp = tmp[i];
1639       /* Must propogate orientation */
1640       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1641       PetscInt       c;
1642 
1643       /* Check for duplicate */
1644       for (c = 0; c < closureSize; c += 2) {
1645         if (closure[c] == cp) break;
1646       }
1647       if (c == closureSize) {
1648         closure[closureSize]   = cp;
1649         closure[closureSize+1] = co;
1650         fifo[fifoSize]         = cp;
1651         fifo[fifoSize+1]       = co;
1652         closureSize           += 2;
1653         fifoSize              += 2;
1654       }
1655     }
1656     fifoStart += 2;
1657   }
1658   if (numPoints) *numPoints = closureSize/2;
1659   if (points)    *points    = closure;
1660   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1661   PetscFunctionReturn(0);
1662 }
1663 
1664 #undef __FUNCT__
1665 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1666 /*@C
1667   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1668 
1669   Not collective
1670 
1671   Input Parameters:
1672 + mesh - The DMPlex
1673 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1674 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1675 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1676 
1677   Output Parameters:
1678 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1679 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1680 
1681   Note:
1682   If not using internal storage (points is not NULL on input), this call is unnecessary
1683 
1684   Level: beginner
1685 
1686 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1687 @*/
1688 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1689 {
1690   PetscErrorCode ierr;
1691 
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1694   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1695   PetscFunctionReturn(0);
1696 }
1697 
1698 #undef __FUNCT__
1699 #define __FUNCT__ "DMPlexGetFaces"
1700 /*
1701   DMPlexGetFaces -
1702 
1703   Note: This will only work for cell-vertex meshes.
1704 */
1705 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1706 {
1707   DM_Plex        *mesh = (DM_Plex*) dm->data;
1708   const PetscInt *cone = NULL;
1709   PetscInt        depth = 0, dim, coneSize;
1710   PetscErrorCode  ierr;
1711 
1712   PetscFunctionBegin;
1713   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1714   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1715   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1716   if (depth > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1717   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1718   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1719   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1720   switch (dim) {
1721   case 2:
1722     switch (coneSize) {
1723     case 3:
1724       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1725       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1726       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1727       *numFaces         = 3;
1728       *faceSize         = 2;
1729       *faces            = mesh->facesTmp;
1730       break;
1731     case 4:
1732       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1733       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1734       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1735       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1736       *numFaces         = 4;
1737       *faceSize         = 2;
1738       *faces            = mesh->facesTmp;
1739       break;
1740     default:
1741       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1742     }
1743     break;
1744   case 3:
1745     switch (coneSize) {
1746     case 3:
1747       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1748       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1749       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1750       *numFaces         = 3;
1751       *faceSize         = 2;
1752       *faces            = mesh->facesTmp;
1753       break;
1754     case 4:
1755       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1756       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1757       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1758       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1759       *numFaces         = 4;
1760       *faceSize         = 3;
1761       *faces            = mesh->facesTmp;
1762       break;
1763     default:
1764       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1765     }
1766     break;
1767   default:
1768     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1769   }
1770   PetscFunctionReturn(0);
1771 }
1772 
1773 #undef __FUNCT__
1774 #define __FUNCT__ "DMPlexGetMaxSizes"
1775 /*@
1776   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1777 
1778   Not collective
1779 
1780   Input Parameter:
1781 . mesh - The DMPlex
1782 
1783   Output Parameters:
1784 + maxConeSize - The maximum number of in-edges
1785 - maxSupportSize - The maximum number of out-edges
1786 
1787   Level: beginner
1788 
1789 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1790 @*/
1791 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1792 {
1793   DM_Plex *mesh = (DM_Plex*) dm->data;
1794 
1795   PetscFunctionBegin;
1796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1797   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1798   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1799   PetscFunctionReturn(0);
1800 }
1801 
1802 #undef __FUNCT__
1803 #define __FUNCT__ "DMSetUp_Plex"
1804 PetscErrorCode DMSetUp_Plex(DM dm)
1805 {
1806   DM_Plex       *mesh = (DM_Plex*) dm->data;
1807   PetscInt       size;
1808   PetscErrorCode ierr;
1809 
1810   PetscFunctionBegin;
1811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1812   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1813   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1814   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1815   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1816   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1817   if (mesh->maxSupportSize) {
1818     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1819     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1820     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1821   }
1822   PetscFunctionReturn(0);
1823 }
1824 
1825 #undef __FUNCT__
1826 #define __FUNCT__ "DMCreateSubDM_Plex"
1827 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1828 {
1829   PetscSection   section, sectionGlobal;
1830   PetscInt      *subIndices;
1831   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1832   PetscErrorCode ierr;
1833 
1834   PetscFunctionBegin;
1835   if (!numFields) PetscFunctionReturn(0);
1836   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1837   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1838   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1839   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1840   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1841   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1842   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1843   for (p = pStart; p < pEnd; ++p) {
1844     PetscInt gdof;
1845 
1846     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1847     if (gdof > 0) {
1848       for (f = 0; f < numFields; ++f) {
1849         PetscInt fdof, fcdof;
1850 
1851         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1852         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1853         subSize += fdof-fcdof;
1854       }
1855     }
1856   }
1857   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1858   for (p = pStart; p < pEnd; ++p) {
1859     PetscInt gdof, goff;
1860 
1861     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1862     if (gdof > 0) {
1863       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1864       for (f = 0; f < numFields; ++f) {
1865         PetscInt fdof, fcdof, fc, f2, poff = 0;
1866 
1867         /* Can get rid of this loop by storing field information in the global section */
1868         for (f2 = 0; f2 < fields[f]; ++f2) {
1869           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1870           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1871           poff += fdof-fcdof;
1872         }
1873         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1874         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1875         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1876           subIndices[subOff] = goff+poff+fc;
1877         }
1878       }
1879     }
1880   }
1881   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1882   if (subdm) {
1883     PetscSection subsection;
1884     PetscBool    haveNull = PETSC_FALSE;
1885     PetscInt     f, nf = 0;
1886 
1887     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1888     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1889     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1890     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1891     for (f = 0; f < numFields; ++f) {
1892       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1893       if ((*subdm)->nullspaceConstructors[f]) {
1894         haveNull = PETSC_TRUE;
1895         nf       = f;
1896       }
1897     }
1898     if (haveNull) {
1899       MatNullSpace nullSpace;
1900 
1901       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1902       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1903       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1904     }
1905     if (dm->fields) {
1906       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1907       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1908       for (f = 0; f < numFields; ++f) {
1909         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1910       }
1911       if (numFields == 1) {
1912         MatNullSpace space;
1913         Mat          pmat;
1914 
1915         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1916         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1917         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1918         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1919         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1920         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1921       }
1922     }
1923   }
1924   PetscFunctionReturn(0);
1925 }
1926 
1927 #undef __FUNCT__
1928 #define __FUNCT__ "DMPlexSymmetrize"
1929 /*@
1930   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1931 
1932   Not collective
1933 
1934   Input Parameter:
1935 . mesh - The DMPlex
1936 
1937   Output Parameter:
1938 
1939   Note:
1940   This should be called after all calls to DMPlexSetCone()
1941 
1942   Level: beginner
1943 
1944 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1945 @*/
1946 PetscErrorCode DMPlexSymmetrize(DM dm)
1947 {
1948   DM_Plex       *mesh = (DM_Plex*) dm->data;
1949   PetscInt      *offsets;
1950   PetscInt       supportSize;
1951   PetscInt       pStart, pEnd, p;
1952   PetscErrorCode ierr;
1953 
1954   PetscFunctionBegin;
1955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1956   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1957   /* Calculate support sizes */
1958   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1959   for (p = pStart; p < pEnd; ++p) {
1960     PetscInt dof, off, c;
1961 
1962     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1963     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1964     for (c = off; c < off+dof; ++c) {
1965       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1966     }
1967   }
1968   for (p = pStart; p < pEnd; ++p) {
1969     PetscInt dof;
1970 
1971     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1972 
1973     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1974   }
1975   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1976   /* Calculate supports */
1977   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1978   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1979   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1980   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1981   for (p = pStart; p < pEnd; ++p) {
1982     PetscInt dof, off, c;
1983 
1984     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1985     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1986     for (c = off; c < off+dof; ++c) {
1987       const PetscInt q = mesh->cones[c];
1988       PetscInt       offS;
1989 
1990       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1991 
1992       mesh->supports[offS+offsets[q]] = p;
1993       ++offsets[q];
1994     }
1995   }
1996   ierr = PetscFree(offsets);CHKERRQ(ierr);
1997   PetscFunctionReturn(0);
1998 }
1999 
2000 #undef __FUNCT__
2001 #define __FUNCT__ "DMPlexSetDepth_Private"
2002 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
2003 {
2004   PetscInt       d;
2005   PetscErrorCode ierr;
2006 
2007   PetscFunctionBegin;
2008   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2009   if (d < 0) {
2010     /* We are guaranteed that the point has a cone since the depth was not yet set */
2011     const PetscInt *cone = NULL;
2012     PetscInt        dCone;
2013 
2014     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2015     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2016     d    = dCone+1;
2017     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2018   }
2019   *depth = d;
2020   PetscFunctionReturn(0);
2021 }
2022 
2023 #undef __FUNCT__
2024 #define __FUNCT__ "DMPlexStratify"
2025 /*@
2026   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2027   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2028   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2029   the DAG.
2030 
2031   Not collective
2032 
2033   Input Parameter:
2034 . mesh - The DMPlex
2035 
2036   Output Parameter:
2037 
2038   Notes:
2039   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2040   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2041 
2042   This should be called after all calls to DMPlexSymmetrize()
2043 
2044   Level: beginner
2045 
2046 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2047 @*/
2048 PetscErrorCode DMPlexStratify(DM dm)
2049 {
2050   DM_Plex       *mesh = (DM_Plex*) dm->data;
2051   PetscInt       pStart, pEnd, p;
2052   PetscInt       numRoots = 0, numLeaves = 0;
2053   PetscErrorCode ierr;
2054 
2055   PetscFunctionBegin;
2056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2057   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2058   /* Calculate depth */
2059   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2060   /* Initialize roots and count leaves */
2061   for (p = pStart; p < pEnd; ++p) {
2062     PetscInt coneSize, supportSize;
2063 
2064     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2065     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2066     if (!coneSize && supportSize) {
2067       ++numRoots;
2068       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2069     } else if (!supportSize && coneSize) {
2070       ++numLeaves;
2071     } else if (!supportSize && !coneSize) {
2072       /* Isolated points */
2073       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2074     }
2075   }
2076   if (numRoots + numLeaves == (pEnd - pStart)) {
2077     for (p = pStart; p < pEnd; ++p) {
2078       PetscInt coneSize, supportSize;
2079 
2080       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2081       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2082       if (!supportSize && coneSize) {
2083         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2084       }
2085     }
2086   } else {
2087     /* This might be slow since lookup is not fast */
2088     for (p = pStart; p < pEnd; ++p) {
2089       PetscInt depth;
2090 
2091       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2092     }
2093   }
2094   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2095   PetscFunctionReturn(0);
2096 }
2097 
2098 #undef __FUNCT__
2099 #define __FUNCT__ "DMPlexGetJoin"
2100 /*@C
2101   DMPlexGetJoin - Get an array for the join of the set of points
2102 
2103   Not Collective
2104 
2105   Input Parameters:
2106 + dm - The DMPlex object
2107 . numPoints - The number of input points for the join
2108 - points - The input points
2109 
2110   Output Parameters:
2111 + numCoveredPoints - The number of points in the join
2112 - coveredPoints - The points in the join
2113 
2114   Level: intermediate
2115 
2116   Note: Currently, this is restricted to a single level join
2117 
2118 .keywords: mesh
2119 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2120 @*/
2121 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2122 {
2123   DM_Plex       *mesh = (DM_Plex*) dm->data;
2124   PetscInt      *join[2];
2125   PetscInt       joinSize, i = 0;
2126   PetscInt       dof, off, p, c, m;
2127   PetscErrorCode ierr;
2128 
2129   PetscFunctionBegin;
2130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2131   PetscValidPointer(points, 2);
2132   PetscValidPointer(numCoveredPoints, 3);
2133   PetscValidPointer(coveredPoints, 4);
2134   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2135   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2136   /* Copy in support of first point */
2137   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2138   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2139   for (joinSize = 0; joinSize < dof; ++joinSize) {
2140     join[i][joinSize] = mesh->supports[off+joinSize];
2141   }
2142   /* Check each successive support */
2143   for (p = 1; p < numPoints; ++p) {
2144     PetscInt newJoinSize = 0;
2145 
2146     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2147     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2148     for (c = 0; c < dof; ++c) {
2149       const PetscInt point = mesh->supports[off+c];
2150 
2151       for (m = 0; m < joinSize; ++m) {
2152         if (point == join[i][m]) {
2153           join[1-i][newJoinSize++] = point;
2154           break;
2155         }
2156       }
2157     }
2158     joinSize = newJoinSize;
2159     i        = 1-i;
2160   }
2161   *numCoveredPoints = joinSize;
2162   *coveredPoints    = join[i];
2163   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2164   PetscFunctionReturn(0);
2165 }
2166 
2167 #undef __FUNCT__
2168 #define __FUNCT__ "DMPlexRestoreJoin"
2169 /*@C
2170   DMPlexRestoreJoin - Restore an array for the join of the set of points
2171 
2172   Not Collective
2173 
2174   Input Parameters:
2175 + dm - The DMPlex object
2176 . numPoints - The number of input points for the join
2177 - points - The input points
2178 
2179   Output Parameters:
2180 + numCoveredPoints - The number of points in the join
2181 - coveredPoints - The points in the join
2182 
2183   Level: intermediate
2184 
2185 .keywords: mesh
2186 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2187 @*/
2188 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2189 {
2190   PetscErrorCode ierr;
2191 
2192   PetscFunctionBegin;
2193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2194   PetscValidPointer(coveredPoints, 4);
2195   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2196   PetscFunctionReturn(0);
2197 }
2198 
2199 #undef __FUNCT__
2200 #define __FUNCT__ "DMPlexGetFullJoin"
2201 /*@C
2202   DMPlexGetFullJoin - Get an array for the join of the set of points
2203 
2204   Not Collective
2205 
2206   Input Parameters:
2207 + dm - The DMPlex object
2208 . numPoints - The number of input points for the join
2209 - points - The input points
2210 
2211   Output Parameters:
2212 + numCoveredPoints - The number of points in the join
2213 - coveredPoints - The points in the join
2214 
2215   Level: intermediate
2216 
2217 .keywords: mesh
2218 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2219 @*/
2220 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2221 {
2222   DM_Plex       *mesh = (DM_Plex*) dm->data;
2223   PetscInt      *offsets, **closures;
2224   PetscInt      *join[2];
2225   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2226   PetscInt       p, d, c, m;
2227   PetscErrorCode ierr;
2228 
2229   PetscFunctionBegin;
2230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2231   PetscValidPointer(points, 2);
2232   PetscValidPointer(numCoveredPoints, 3);
2233   PetscValidPointer(coveredPoints, 4);
2234 
2235   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2236   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2237   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2238   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2239   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2240   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2241   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2242 
2243   for (p = 0; p < numPoints; ++p) {
2244     PetscInt closureSize;
2245 
2246     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2247 
2248     offsets[p*(depth+2)+0] = 0;
2249     for (d = 0; d < depth+1; ++d) {
2250       PetscInt pStart, pEnd, i;
2251 
2252       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2253       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2254         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2255           offsets[p*(depth+2)+d+1] = i;
2256           break;
2257         }
2258       }
2259       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2260     }
2261     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);
2262   }
2263   for (d = 0; d < depth+1; ++d) {
2264     PetscInt dof;
2265 
2266     /* Copy in support of first point */
2267     dof = offsets[d+1] - offsets[d];
2268     for (joinSize = 0; joinSize < dof; ++joinSize) {
2269       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2270     }
2271     /* Check each successive cone */
2272     for (p = 1; p < numPoints && joinSize; ++p) {
2273       PetscInt newJoinSize = 0;
2274 
2275       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2276       for (c = 0; c < dof; ++c) {
2277         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2278 
2279         for (m = 0; m < joinSize; ++m) {
2280           if (point == join[i][m]) {
2281             join[1-i][newJoinSize++] = point;
2282             break;
2283           }
2284         }
2285       }
2286       joinSize = newJoinSize;
2287       i        = 1-i;
2288     }
2289     if (joinSize) break;
2290   }
2291   *numCoveredPoints = joinSize;
2292   *coveredPoints    = join[i];
2293   for (p = 0; p < numPoints; ++p) {
2294     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2295   }
2296   ierr = PetscFree(closures);CHKERRQ(ierr);
2297   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2298   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2299   PetscFunctionReturn(0);
2300 }
2301 
2302 #undef __FUNCT__
2303 #define __FUNCT__ "DMPlexGetMeet"
2304 /*@C
2305   DMPlexGetMeet - Get an array for the meet of the set of points
2306 
2307   Not Collective
2308 
2309   Input Parameters:
2310 + dm - The DMPlex object
2311 . numPoints - The number of input points for the meet
2312 - points - The input points
2313 
2314   Output Parameters:
2315 + numCoveredPoints - The number of points in the meet
2316 - coveredPoints - The points in the meet
2317 
2318   Level: intermediate
2319 
2320   Note: Currently, this is restricted to a single level meet
2321 
2322 .keywords: mesh
2323 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2324 @*/
2325 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2326 {
2327   DM_Plex       *mesh = (DM_Plex*) dm->data;
2328   PetscInt      *meet[2];
2329   PetscInt       meetSize, i = 0;
2330   PetscInt       dof, off, p, c, m;
2331   PetscErrorCode ierr;
2332 
2333   PetscFunctionBegin;
2334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2335   PetscValidPointer(points, 2);
2336   PetscValidPointer(numCoveringPoints, 3);
2337   PetscValidPointer(coveringPoints, 4);
2338   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2339   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2340   /* Copy in cone of first point */
2341   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2342   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2343   for (meetSize = 0; meetSize < dof; ++meetSize) {
2344     meet[i][meetSize] = mesh->cones[off+meetSize];
2345   }
2346   /* Check each successive cone */
2347   for (p = 1; p < numPoints; ++p) {
2348     PetscInt newMeetSize = 0;
2349 
2350     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2351     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2352     for (c = 0; c < dof; ++c) {
2353       const PetscInt point = mesh->cones[off+c];
2354 
2355       for (m = 0; m < meetSize; ++m) {
2356         if (point == meet[i][m]) {
2357           meet[1-i][newMeetSize++] = point;
2358           break;
2359         }
2360       }
2361     }
2362     meetSize = newMeetSize;
2363     i        = 1-i;
2364   }
2365   *numCoveringPoints = meetSize;
2366   *coveringPoints    = meet[i];
2367   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2368   PetscFunctionReturn(0);
2369 }
2370 
2371 #undef __FUNCT__
2372 #define __FUNCT__ "DMPlexRestoreMeet"
2373 /*@C
2374   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2375 
2376   Not Collective
2377 
2378   Input Parameters:
2379 + dm - The DMPlex object
2380 . numPoints - The number of input points for the meet
2381 - points - The input points
2382 
2383   Output Parameters:
2384 + numCoveredPoints - The number of points in the meet
2385 - coveredPoints - The points in the meet
2386 
2387   Level: intermediate
2388 
2389 .keywords: mesh
2390 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2391 @*/
2392 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2393 {
2394   PetscErrorCode ierr;
2395 
2396   PetscFunctionBegin;
2397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2398   PetscValidPointer(coveredPoints, 4);
2399   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2400   PetscFunctionReturn(0);
2401 }
2402 
2403 #undef __FUNCT__
2404 #define __FUNCT__ "DMPlexGetFullMeet"
2405 /*@C
2406   DMPlexGetFullMeet - Get an array for the meet of the set of points
2407 
2408   Not Collective
2409 
2410   Input Parameters:
2411 + dm - The DMPlex object
2412 . numPoints - The number of input points for the meet
2413 - points - The input points
2414 
2415   Output Parameters:
2416 + numCoveredPoints - The number of points in the meet
2417 - coveredPoints - The points in the meet
2418 
2419   Level: intermediate
2420 
2421 .keywords: mesh
2422 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2423 @*/
2424 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2425 {
2426   DM_Plex       *mesh = (DM_Plex*) dm->data;
2427   PetscInt      *offsets, **closures;
2428   PetscInt      *meet[2];
2429   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2430   PetscInt       p, h, c, m;
2431   PetscErrorCode ierr;
2432 
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2435   PetscValidPointer(points, 2);
2436   PetscValidPointer(numCoveredPoints, 3);
2437   PetscValidPointer(coveredPoints, 4);
2438 
2439   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2440   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2441   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2442   maxSize = PetscPowInt(mesh->maxConeSize,height);
2443   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2444   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2445 
2446   for (p = 0; p < numPoints; ++p) {
2447     PetscInt closureSize;
2448 
2449     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2450 
2451     offsets[p*(height+2)+0] = 0;
2452     for (h = 0; h < height+1; ++h) {
2453       PetscInt pStart, pEnd, i;
2454 
2455       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2456       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2457         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2458           offsets[p*(height+2)+h+1] = i;
2459           break;
2460         }
2461       }
2462       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2463     }
2464     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);
2465   }
2466   for (h = 0; h < height+1; ++h) {
2467     PetscInt dof;
2468 
2469     /* Copy in cone of first point */
2470     dof = offsets[h+1] - offsets[h];
2471     for (meetSize = 0; meetSize < dof; ++meetSize) {
2472       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2473     }
2474     /* Check each successive cone */
2475     for (p = 1; p < numPoints && meetSize; ++p) {
2476       PetscInt newMeetSize = 0;
2477 
2478       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2479       for (c = 0; c < dof; ++c) {
2480         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2481 
2482         for (m = 0; m < meetSize; ++m) {
2483           if (point == meet[i][m]) {
2484             meet[1-i][newMeetSize++] = point;
2485             break;
2486           }
2487         }
2488       }
2489       meetSize = newMeetSize;
2490       i        = 1-i;
2491     }
2492     if (meetSize) break;
2493   }
2494   *numCoveredPoints = meetSize;
2495   *coveredPoints    = meet[i];
2496   for (p = 0; p < numPoints; ++p) {
2497     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2498   }
2499   ierr = PetscFree(closures);CHKERRQ(ierr);
2500   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2501   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2502   PetscFunctionReturn(0);
2503 }
2504 
2505 #undef __FUNCT__
2506 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2507 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2508 {
2509   MPI_Comm       comm;
2510   PetscInt       cellDim;
2511   PetscErrorCode ierr;
2512 
2513   PetscFunctionBegin;
2514   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2515   PetscValidPointer(numFaceVertices,3);
2516   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2517   switch (cellDim) {
2518   case 0:
2519     *numFaceVertices = 0;
2520     break;
2521   case 1:
2522     *numFaceVertices = 1;
2523     break;
2524   case 2:
2525     switch (numCorners) {
2526     case 3: /* triangle */
2527       *numFaceVertices = 2; /* Edge has 2 vertices */
2528       break;
2529     case 4: /* quadrilateral */
2530       *numFaceVertices = 2; /* Edge has 2 vertices */
2531       break;
2532     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2533       *numFaceVertices = 3; /* Edge has 3 vertices */
2534       break;
2535     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2536       *numFaceVertices = 3; /* Edge has 3 vertices */
2537       break;
2538     default:
2539       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2540     }
2541     break;
2542   case 3:
2543     switch (numCorners) {
2544     case 4: /* tetradehdron */
2545       *numFaceVertices = 3; /* Face has 3 vertices */
2546       break;
2547     case 6: /* tet cohesive cells */
2548       *numFaceVertices = 4; /* Face has 4 vertices */
2549       break;
2550     case 8: /* hexahedron */
2551       *numFaceVertices = 4; /* Face has 4 vertices */
2552       break;
2553     case 9: /* tet cohesive Lagrange cells */
2554       *numFaceVertices = 6; /* Face has 6 vertices */
2555       break;
2556     case 10: /* quadratic tetrahedron */
2557       *numFaceVertices = 6; /* Face has 6 vertices */
2558       break;
2559     case 12: /* hex cohesive Lagrange cells */
2560       *numFaceVertices = 6; /* Face has 6 vertices */
2561       break;
2562     case 18: /* quadratic tet cohesive Lagrange cells */
2563       *numFaceVertices = 6; /* Face has 6 vertices */
2564       break;
2565     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2566       *numFaceVertices = 9; /* Face has 9 vertices */
2567       break;
2568     default:
2569       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2570     }
2571     break;
2572   default:
2573     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2574   }
2575   PetscFunctionReturn(0);
2576 }
2577 
2578 #undef __FUNCT__
2579 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2580 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2581 {
2582   const PetscInt maxFaceCases = 30;
2583   PetscInt       numFaceCases = 0;
2584   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2585   PetscInt      *off, *adj;
2586   PetscInt      *neighborCells, *tmpClosure;
2587   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2588   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2589   PetscErrorCode ierr;
2590 
2591   PetscFunctionBegin;
2592   /* For parallel partitioning, I think you have to communicate supports */
2593   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2594   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2595   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2596   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2597   if (cEnd - cStart == 0) {
2598     if (numVertices) *numVertices = 0;
2599     if (offsets)   *offsets   = NULL;
2600     if (adjacency) *adjacency = NULL;
2601     PetscFunctionReturn(0);
2602   }
2603   numCells = cEnd - cStart;
2604   /* Setup face recognition */
2605   if (depth == 1) {
2606     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 */
2607 
2608     for (c = cStart; c < cEnd; ++c) {
2609       PetscInt corners;
2610 
2611       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2612       if (!cornersSeen[corners]) {
2613         PetscInt nFV;
2614 
2615         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2616         cornersSeen[corners] = 1;
2617 
2618         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2619 
2620         numFaceVertices[numFaceCases++] = nFV;
2621       }
2622     }
2623   }
2624   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2625   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2626   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2627   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2628   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2629   /* Count neighboring cells */
2630   for (cell = cStart; cell < cEnd; ++cell) {
2631     PetscInt numNeighbors = maxNeighbors, n;
2632 
2633     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2634     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2635     for (n = 0; n < numNeighbors; ++n) {
2636       PetscInt        cellPair[2];
2637       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2638       PetscInt        meetSize = 0;
2639       const PetscInt *meet    = NULL;
2640 
2641       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2642       if (cellPair[0] == cellPair[1]) continue;
2643       if (!found) {
2644         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2645         if (meetSize) {
2646           PetscInt f;
2647 
2648           for (f = 0; f < numFaceCases; ++f) {
2649             if (numFaceVertices[f] == meetSize) {
2650               found = PETSC_TRUE;
2651               break;
2652             }
2653           }
2654         }
2655         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656       }
2657       if (found) ++off[cell-cStart+1];
2658     }
2659   }
2660   /* Prefix sum */
2661   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2662 
2663   if (adjacency) {
2664     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2665     /* Get neighboring cells */
2666     for (cell = cStart; cell < cEnd; ++cell) {
2667       PetscInt numNeighbors = maxNeighbors, n;
2668       PetscInt cellOffset   = 0;
2669 
2670       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2671       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2672       for (n = 0; n < numNeighbors; ++n) {
2673         PetscInt        cellPair[2];
2674         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2675         PetscInt        meetSize = 0;
2676         const PetscInt *meet    = NULL;
2677 
2678         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2679         if (cellPair[0] == cellPair[1]) continue;
2680         if (!found) {
2681           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2682           if (meetSize) {
2683             PetscInt f;
2684 
2685             for (f = 0; f < numFaceCases; ++f) {
2686               if (numFaceVertices[f] == meetSize) {
2687                 found = PETSC_TRUE;
2688                 break;
2689               }
2690             }
2691           }
2692           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2693         }
2694         if (found) {
2695           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2696           ++cellOffset;
2697         }
2698       }
2699     }
2700   }
2701   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2702   if (numVertices) *numVertices = numCells;
2703   if (offsets)   *offsets   = off;
2704   if (adjacency) *adjacency = adj;
2705   PetscFunctionReturn(0);
2706 }
2707 
2708 #if defined(PETSC_HAVE_CHACO)
2709 #if defined(PETSC_HAVE_UNISTD_H)
2710 #include <unistd.h>
2711 #endif
2712 /* Chaco does not have an include file */
2713 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2714                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2715                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2716                        int mesh_dims[3], double *goal, int global_method, int local_method,
2717                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2718 
2719 extern int FREE_GRAPH;
2720 
2721 #undef __FUNCT__
2722 #define __FUNCT__ "DMPlexPartition_Chaco"
2723 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2724 {
2725   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2726   MPI_Comm       comm;
2727   int            nvtxs          = numVertices; /* number of vertices in full graph */
2728   int           *vwgts          = NULL;   /* weights for all vertices */
2729   float         *ewgts          = NULL;   /* weights for all edges */
2730   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2731   char          *outassignname  = NULL;   /*  name of assignment output file */
2732   char          *outfilename    = NULL;   /* output file name */
2733   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2734   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2735   int            mesh_dims[3];            /* dimensions of mesh of processors */
2736   double        *goal          = NULL;    /* desired set sizes for each set */
2737   int            global_method = 1;       /* global partitioning algorithm */
2738   int            local_method  = 1;       /* local partitioning algorithm */
2739   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2740   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2741   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2742   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2743   long           seed          = 123636512; /* for random graph mutations */
2744   short int     *assignment;              /* Output partition */
2745   int            fd_stdout, fd_pipe[2];
2746   PetscInt      *points;
2747   PetscMPIInt    commSize;
2748   int            i, v, p;
2749   PetscErrorCode ierr;
2750 
2751   PetscFunctionBegin;
2752   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2753   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2754   if (!numVertices) {
2755     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2756     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2757     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2758     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2759     PetscFunctionReturn(0);
2760   }
2761   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2762   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2763 
2764   if (global_method == INERTIAL_METHOD) {
2765     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2766     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2767   }
2768   mesh_dims[0] = commSize;
2769   mesh_dims[1] = 1;
2770   mesh_dims[2] = 1;
2771   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2772   /* Chaco outputs to stdout. We redirect this to a buffer. */
2773   /* TODO: check error codes for UNIX calls */
2774 #if defined(PETSC_HAVE_UNISTD_H)
2775   {
2776     int piperet;
2777     piperet = pipe(fd_pipe);
2778     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2779     fd_stdout = dup(1);
2780     close(1);
2781     dup2(fd_pipe[1], 1);
2782   }
2783 #endif
2784   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2785                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2786                    vmax, ndims, eigtol, seed);
2787 #if defined(PETSC_HAVE_UNISTD_H)
2788   {
2789     char msgLog[10000];
2790     int  count;
2791 
2792     fflush(stdout);
2793     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2794     if (count < 0) count = 0;
2795     msgLog[count] = 0;
2796     close(1);
2797     dup2(fd_stdout, 1);
2798     close(fd_stdout);
2799     close(fd_pipe[0]);
2800     close(fd_pipe[1]);
2801     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2802   }
2803 #endif
2804   /* Convert to PetscSection+IS */
2805   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2806   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2807   for (v = 0; v < nvtxs; ++v) {
2808     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2809   }
2810   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2811   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2812   for (p = 0, i = 0; p < commSize; ++p) {
2813     for (v = 0; v < nvtxs; ++v) {
2814       if (assignment[v] == p) points[i++] = v;
2815     }
2816   }
2817   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2818   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2819   if (global_method == INERTIAL_METHOD) {
2820     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2821   }
2822   ierr = PetscFree(assignment);CHKERRQ(ierr);
2823   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2824   PetscFunctionReturn(0);
2825 }
2826 #endif
2827 
2828 #if defined(PETSC_HAVE_PARMETIS)
2829 #undef __FUNCT__
2830 #define __FUNCT__ "DMPlexPartition_ParMetis"
2831 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2832 {
2833   PetscFunctionBegin;
2834   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2835   PetscFunctionReturn(0);
2836 }
2837 #endif
2838 
2839 #undef __FUNCT__
2840 #define __FUNCT__ "DMPlexEnlargePartition"
2841 /* Expand the partition by BFS on the adjacency graph */
2842 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2843 {
2844   PetscHashI      h;
2845   const PetscInt *points;
2846   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2847   PetscInt        pStart, pEnd, part, q;
2848   PetscErrorCode  ierr;
2849 
2850   PetscFunctionBegin;
2851   PetscHashICreate(h);
2852   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2853   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2854   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2855   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2856   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2857   for (part = pStart; part < pEnd; ++part) {
2858     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2859 
2860     PetscHashIClear(h);
2861     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2862     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2863     /* Add all existing points to h */
2864     for (p = 0; p < numPoints; ++p) {
2865       const PetscInt point = points[off+p];
2866       PetscHashIAdd(h, point, 1);
2867     }
2868     PetscHashISize(h, nP);
2869     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2870     /* Add all points in next BFS level */
2871     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2872     for (p = 0; p < numPoints; ++p) {
2873       const PetscInt point = points[off+p];
2874       PetscInt       s     = start[point], e = start[point+1], a;
2875 
2876       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2877     }
2878     PetscHashISize(h, numNewPoints);
2879     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2880     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2881     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2882     totPoints += numNewPoints;
2883   }
2884   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2885   PetscHashIDestroy(h);
2886   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2887   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2888   for (part = pStart, q = 0; part < pEnd; ++part) {
2889     PetscInt numPoints, p;
2890 
2891     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2892     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2893     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2894   }
2895   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2896   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2897   PetscFunctionReturn(0);
2898 }
2899 
2900 #undef __FUNCT__
2901 #define __FUNCT__ "DMPlexCreatePartition"
2902 /*
2903   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2904 
2905   Collective on DM
2906 
2907   Input Parameters:
2908   + dm - The DM
2909   . height - The height for points in the partition
2910   - enlarge - Expand each partition with neighbors
2911 
2912   Output Parameters:
2913   + partSection - The PetscSection giving the division of points by partition
2914   . partition - The list of points by partition
2915   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2916   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2917 
2918   Level: developer
2919 
2920 .seealso DMPlexDistribute()
2921 */
2922 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2923 {
2924   PetscMPIInt    size;
2925   PetscErrorCode ierr;
2926 
2927   PetscFunctionBegin;
2928   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2929 
2930   *origPartSection = NULL;
2931   *origPartition   = NULL;
2932   if (size == 1) {
2933     PetscInt *points;
2934     PetscInt  cStart, cEnd, c;
2935 
2936     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2937     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2938     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2939     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2940     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2941     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2942     for (c = cStart; c < cEnd; ++c) points[c] = c;
2943     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2944     PetscFunctionReturn(0);
2945   }
2946   if (height == 0) {
2947     PetscInt  numVertices;
2948     PetscInt *start     = NULL;
2949     PetscInt *adjacency = NULL;
2950 
2951     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2952     if (1) {
2953 #if defined(PETSC_HAVE_CHACO)
2954       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2955 #endif
2956     } else {
2957 #if defined(PETSC_HAVE_PARMETIS)
2958       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2959 #endif
2960     }
2961     if (enlarge) {
2962       *origPartSection = *partSection;
2963       *origPartition   = *partition;
2964 
2965       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2966     }
2967     ierr = PetscFree(start);CHKERRQ(ierr);
2968     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2969 # if 0
2970   } else if (height == 1) {
2971     /* Build the dual graph for faces and partition the hypergraph */
2972     PetscInt numEdges;
2973 
2974     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2975     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2976     destroyCSR(numEdges, start, adjacency);
2977 #endif
2978   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2979   PetscFunctionReturn(0);
2980 }
2981 
2982 #undef __FUNCT__
2983 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2984 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2985 {
2986   /* const PetscInt  height = 0; */
2987   const PetscInt *partArray;
2988   PetscInt       *allPoints, *partPoints = NULL;
2989   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2990   PetscErrorCode  ierr;
2991 
2992   PetscFunctionBegin;
2993   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2994   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2995   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2996   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2997   for (rank = rStart; rank < rEnd; ++rank) {
2998     PetscInt partSize = 0;
2999     PetscInt numPoints, offset, p;
3000 
3001     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3002     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3003     for (p = 0; p < numPoints; ++p) {
3004       PetscInt  point   = partArray[offset+p], closureSize, c;
3005       PetscInt *closure = NULL;
3006 
3007       /* TODO Include support for height > 0 case */
3008       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3009       /* Merge into existing points */
3010       if (partSize+closureSize > maxPartSize) {
3011         PetscInt *tmpPoints;
3012 
3013         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3014         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3015         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3016         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3017 
3018         partPoints = tmpPoints;
3019       }
3020       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3021       partSize += closureSize;
3022 
3023       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3024       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3025     }
3026     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3027   }
3028   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3029   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3030   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3031 
3032   for (rank = rStart; rank < rEnd; ++rank) {
3033     PetscInt partSize = 0, newOffset;
3034     PetscInt numPoints, offset, p;
3035 
3036     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3037     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3038     for (p = 0; p < numPoints; ++p) {
3039       PetscInt  point   = partArray[offset+p], closureSize, c;
3040       PetscInt *closure = NULL;
3041 
3042       /* TODO Include support for height > 0 case */
3043       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3044       /* Merge into existing points */
3045       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3046       partSize += closureSize;
3047 
3048       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3049       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3050     }
3051     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3052     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3053   }
3054   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3055   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3056   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3057   PetscFunctionReturn(0);
3058 }
3059 
3060 #undef __FUNCT__
3061 #define __FUNCT__ "DMPlexDistributeField"
3062 /*
3063   Input Parameters:
3064 . originalSection
3065 , originalVec
3066 
3067   Output Parameters:
3068 . newSection
3069 . newVec
3070 */
3071 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3072 {
3073   PetscSF        fieldSF;
3074   PetscInt      *remoteOffsets, fieldSize;
3075   PetscScalar   *originalValues, *newValues;
3076   PetscErrorCode ierr;
3077 
3078   PetscFunctionBegin;
3079   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3080 
3081   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3082   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3083   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3084 
3085   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3086   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3087   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3088   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3089   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3090   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3091   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3092   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3093   PetscFunctionReturn(0);
3094 }
3095 
3096 #undef __FUNCT__
3097 #define __FUNCT__ "DMPlexDistribute"
3098 /*@C
3099   DMPlexDistribute - Distributes the mesh and any associated sections.
3100 
3101   Not Collective
3102 
3103   Input Parameter:
3104 + dm  - The original DMPlex object
3105 . partitioner - The partitioning package, or NULL for the default
3106 - overlap - The overlap of partitions, 0 is the default
3107 
3108   Output Parameter:
3109 . parallelMesh - The distributed DMPlex object, or NULL
3110 
3111   Note: If the mesh was not distributed, the return value is NULL
3112 
3113   Level: intermediate
3114 
3115 .keywords: mesh, elements
3116 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3117 @*/
3118 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3119 {
3120   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3121   MPI_Comm               comm;
3122   const PetscInt         height = 0;
3123   PetscInt               dim, numRemoteRanks;
3124   IS                     origCellPart,        cellPart,        part;
3125   PetscSection           origCellPartSection, cellPartSection, partSection;
3126   PetscSFNode           *remoteRanks;
3127   PetscSF                partSF, pointSF, coneSF;
3128   ISLocalToGlobalMapping renumbering;
3129   PetscSection           originalConeSection, newConeSection;
3130   PetscInt              *remoteOffsets;
3131   PetscInt              *cones, *newCones, newConesSize;
3132   PetscBool              flg;
3133   PetscMPIInt            rank, numProcs, p;
3134   PetscErrorCode         ierr;
3135 
3136   PetscFunctionBegin;
3137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3138   PetscValidPointer(dmParallel,4);
3139 
3140   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3141   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3142   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3143   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3144 
3145   *dmParallel = NULL;
3146   if (numProcs == 1) PetscFunctionReturn(0);
3147 
3148   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3149   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3150   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3151   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3152   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3153   if (!rank) numRemoteRanks = numProcs;
3154   else       numRemoteRanks = 0;
3155   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3156   for (p = 0; p < numRemoteRanks; ++p) {
3157     remoteRanks[p].rank  = p;
3158     remoteRanks[p].index = 0;
3159   }
3160   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3161   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3162   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3163   if (flg) {
3164     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3165     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3166     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3167     if (origCellPart) {
3168       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3169       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3170       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3171     }
3172     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3173   }
3174   /* Close the partition over the mesh */
3175   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3176   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3177   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3178   /* Create new mesh */
3179   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3180   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3181   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3182   pmesh = (DM_Plex*) (*dmParallel)->data;
3183   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3184   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3185   if (flg) {
3186     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3187     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3188     ierr = ISView(part, NULL);CHKERRQ(ierr);
3189     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3190     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3191     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3192   }
3193   /* Distribute cone section */
3194   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3195   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3196   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3197   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3198   {
3199     PetscInt pStart, pEnd, p;
3200 
3201     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3202     for (p = pStart; p < pEnd; ++p) {
3203       PetscInt coneSize;
3204       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3205       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3206     }
3207   }
3208   /* Communicate and renumber cones */
3209   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3210   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3211   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3212   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3213   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3214   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3215   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3216   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3217   if (flg) {
3218     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3219     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3220     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3221     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3222     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3223   }
3224   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3225   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3226   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3227   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3228   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3229   /* Create supports and stratify sieve */
3230   {
3231     PetscInt pStart, pEnd;
3232 
3233     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3234     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3235   }
3236   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3237   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3238   /* Distribute Coordinates */
3239   {
3240     PetscSection originalCoordSection, newCoordSection;
3241     Vec          originalCoordinates, newCoordinates;
3242     const char  *name;
3243 
3244     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3245     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3246     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3247     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3248     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3249     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3250 
3251     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3252     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3253     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3254   }
3255   /* Distribute labels */
3256   {
3257     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3258     PetscInt numLabels = 0, l;
3259 
3260     /* Bcast number of labels */
3261     while (next) {
3262       ++numLabels; next = next->next;
3263     }
3264     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3265     next = mesh->labels;
3266     for (l = 0; l < numLabels; ++l) {
3267       DMLabel         newLabel;
3268       const PetscInt *partArray;
3269       char           *name;
3270       PetscInt       *stratumSizes = NULL, *points = NULL;
3271       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3272       PetscInt        nameSize, s, p;
3273       PetscBool       isdepth;
3274       size_t          len = 0;
3275 
3276       /* Bcast name (could filter for no points) */
3277       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3278       nameSize = len;
3279       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3280       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3281       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3282       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3283       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3284       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3285       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3286       newLabel->name = name;
3287       /* Bcast numStrata (could filter for no points in stratum) */
3288       if (!rank) newLabel->numStrata = next->numStrata;
3289       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3290       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3291                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3292                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3293       /* Bcast stratumValues (could filter for no points in stratum) */
3294       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3295       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3296       /* Find size on each process and Scatter */
3297       if (!rank) {
3298         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3299         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3300         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3301         for (s = 0; s < next->numStrata; ++s) {
3302           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3303             const PetscInt point = next->points[p];
3304             PetscInt       proc;
3305 
3306             for (proc = 0; proc < numProcs; ++proc) {
3307               PetscInt dof, off, pPart;
3308 
3309               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3310               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3311               for (pPart = off; pPart < off+dof; ++pPart) {
3312                 if (partArray[pPart] == point) {
3313                   ++stratumSizes[proc*next->numStrata+s];
3314                   break;
3315                 }
3316               }
3317             }
3318           }
3319         }
3320         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3321       }
3322       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3323       /* Calculate stratumOffsets */
3324       newLabel->stratumOffsets[0] = 0;
3325       for (s = 0; s < newLabel->numStrata; ++s) {
3326         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3327       }
3328       /* Pack points and Scatter */
3329       if (!rank) {
3330         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3331         displs[0] = 0;
3332         for (p = 0; p < numProcs; ++p) {
3333           sendcnts[p] = 0;
3334           for (s = 0; s < next->numStrata; ++s) {
3335             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3336           }
3337           offsets[p]  = displs[p];
3338           displs[p+1] = displs[p] + sendcnts[p];
3339         }
3340         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3341         for (s = 0; s < next->numStrata; ++s) {
3342           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3343             const PetscInt point = next->points[p];
3344             PetscInt       proc;
3345 
3346             for (proc = 0; proc < numProcs; ++proc) {
3347               PetscInt dof, off, pPart;
3348 
3349               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3350               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3351               for (pPart = off; pPart < off+dof; ++pPart) {
3352                 if (partArray[pPart] == point) {
3353                   points[offsets[proc]++] = point;
3354                   break;
3355                 }
3356               }
3357             }
3358           }
3359         }
3360       }
3361       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3362       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3363       ierr = PetscFree(points);CHKERRQ(ierr);
3364       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3365       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3366       /* Renumber points */
3367       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3368       /* Sort points */
3369       for (s = 0; s < newLabel->numStrata; ++s) {
3370         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3371       }
3372       /* Insert into list */
3373       if (newNext) newNext->next = newLabel;
3374       else pmesh->labels = newLabel;
3375       newNext = newLabel;
3376       if (!rank) next = next->next;
3377     }
3378   }
3379   /* Cleanup Partition */
3380   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3381   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3382   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3383   ierr = ISDestroy(&part);CHKERRQ(ierr);
3384   /* Create point SF for parallel mesh */
3385   {
3386     const PetscInt *leaves;
3387     PetscSFNode    *remotePoints, *rowners, *lowners;
3388     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3389     PetscInt        pStart, pEnd;
3390 
3391     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3392     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3393     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3394     for (p=0; p<numRoots; p++) {
3395       rowners[p].rank  = -1;
3396       rowners[p].index = -1;
3397     }
3398     if (origCellPart) {
3399       /* Make sure cells in the original partition are not assigned to other procs */
3400       const PetscInt *origCells;
3401 
3402       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3403       for (p = 0; p < numProcs; ++p) {
3404         PetscInt dof, off, d;
3405 
3406         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3407         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3408         for (d = off; d < off+dof; ++d) {
3409           rowners[origCells[d]].rank = p;
3410         }
3411       }
3412       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3413     }
3414     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3415     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3416 
3417     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3419     for (p = 0; p < numLeaves; ++p) {
3420       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3421         lowners[p].rank  = rank;
3422         lowners[p].index = leaves ? leaves[p] : p;
3423       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3424         lowners[p].rank  = -2;
3425         lowners[p].index = -2;
3426       }
3427     }
3428     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3429       rowners[p].rank  = -3;
3430       rowners[p].index = -3;
3431     }
3432     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3433     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3434     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3435     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3436     for (p = 0; p < numLeaves; ++p) {
3437       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3438       if (lowners[p].rank != rank) ++numGhostPoints;
3439     }
3440     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3441     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3442     for (p = 0, gp = 0; p < numLeaves; ++p) {
3443       if (lowners[p].rank != rank) {
3444         ghostPoints[gp]        = leaves ? leaves[p] : p;
3445         remotePoints[gp].rank  = lowners[p].rank;
3446         remotePoints[gp].index = lowners[p].index;
3447         ++gp;
3448       }
3449     }
3450     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3451     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3452     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3453   }
3454   /* Cleanup */
3455   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3456   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3457   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3458   PetscFunctionReturn(0);
3459 }
3460 
3461 #undef __FUNCT__
3462 #define __FUNCT__ "DMPlexRenumber_Private"
3463 /*
3464   Reasons to renumber:
3465 
3466   1) Permute points, e.g. bandwidth reduction (Renumber)
3467 
3468     a) Must not mix strata
3469 
3470   2) Shift numbers for point insertion (Shift)
3471 
3472     a) Want operation brken into parts so that insertion can be interleaved
3473 
3474   renumbering - An IS which provides the new numbering
3475 */
3476 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3477 {
3478   PetscFunctionBegin;
3479   PetscFunctionReturn(0);
3480 }
3481 
3482 #undef __FUNCT__
3483 #define __FUNCT__ "DMPlexShiftPoint_Private"
3484 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3485 {
3486   if (depth < 0) return p;
3487   /* Cells    */ if (p < depthEnd[depth])   return p;
3488   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3489   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3490   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3491 }
3492 
3493 #undef __FUNCT__
3494 #define __FUNCT__ "DMPlexShiftSizes_Private"
3495 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3496 {
3497   PetscInt      *depthEnd;
3498   PetscInt       depth = 0, d, pStart, pEnd, p;
3499   PetscErrorCode ierr;
3500 
3501   PetscFunctionBegin;
3502   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3503   if (depth < 0) PetscFunctionReturn(0);
3504   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3505   /* Step 1: Expand chart */
3506   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3507   for (d = 0; d <= depth; ++d) {
3508     pEnd += depthShift[d];
3509     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3510   }
3511   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3512   /* Step 2: Set cone and support sizes */
3513   for (d = 0; d <= depth; ++d) {
3514     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3515     for (p = pStart; p < pEnd; ++p) {
3516       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3517       PetscInt size;
3518 
3519       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3520       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3521       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3522       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3523     }
3524   }
3525   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3526   PetscFunctionReturn(0);
3527 }
3528 
3529 #undef __FUNCT__
3530 #define __FUNCT__ "DMPlexShiftPoints_Private"
3531 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3532 {
3533   PetscInt      *depthEnd, *newpoints;
3534   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3535   PetscErrorCode ierr;
3536 
3537   PetscFunctionBegin;
3538   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3539   if (depth < 0) PetscFunctionReturn(0);
3540   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3541   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3542   for (d = 0; d <= depth; ++d) {
3543     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3544   }
3545   /* Step 5: Set cones and supports */
3546   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3547   for (p = pStart; p < pEnd; ++p) {
3548     const PetscInt *points = NULL, *orientations = NULL;
3549     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3550 
3551     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3552     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3553     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3554     for (i = 0; i < size; ++i) {
3555       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3556     }
3557     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3558     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3559     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3560     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3561     for (i = 0; i < size; ++i) {
3562       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3563     }
3564     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3565   }
3566   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3567   PetscFunctionReturn(0);
3568 }
3569 
3570 #undef __FUNCT__
3571 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3572 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3573 {
3574   PetscSection   coordSection, newCoordSection;
3575   Vec            coordinates, newCoordinates;
3576   PetscScalar   *coords, *newCoords;
3577   PetscInt      *depthEnd, coordSize;
3578   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3579   PetscErrorCode ierr;
3580 
3581   PetscFunctionBegin;
3582   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3583   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3584   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3585   for (d = 0; d <= depth; ++d) {
3586     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3587   }
3588   /* Step 8: Convert coordinates */
3589   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3590   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3591   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3592   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3593   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3594   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3595   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3596   for (v = vStartNew; v < vEndNew; ++v) {
3597     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3598     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3599   }
3600   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3601   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3602   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3603   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3604   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3605   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3606   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3607   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3608   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3609   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3610   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3611   for (v = vStart; v < vEnd; ++v) {
3612     PetscInt dof, off, noff, d;
3613 
3614     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3615     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3616     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3617     for (d = 0; d < dof; ++d) {
3618       newCoords[noff+d] = coords[off+d];
3619     }
3620   }
3621   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3622   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3623   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3624   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3625   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3626   PetscFunctionReturn(0);
3627 }
3628 
3629 #undef __FUNCT__
3630 #define __FUNCT__ "DMPlexShiftSF_Private"
3631 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3632 {
3633   PetscInt          *depthEnd;
3634   PetscInt           depth = 0, d;
3635   PetscSF            sfPoint, sfPointNew;
3636   const PetscSFNode *remotePoints;
3637   PetscSFNode       *gremotePoints;
3638   const PetscInt    *localPoints;
3639   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3640   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3641   PetscMPIInt        numProcs;
3642   PetscErrorCode     ierr;
3643 
3644   PetscFunctionBegin;
3645   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3646   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3647   for (d = 0; d <= depth; ++d) {
3648     totShift += depthShift[d];
3649     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3650   }
3651   /* Step 9: Convert pointSF */
3652   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3653   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3654   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3655   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3656   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3657   if (numRoots >= 0) {
3658     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3659     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3660     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3661     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3662     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3663     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3664     for (l = 0; l < numLeaves; ++l) {
3665       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3666       gremotePoints[l].rank  = remotePoints[l].rank;
3667       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3668     }
3669     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3670     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3671   }
3672   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3673   PetscFunctionReturn(0);
3674 }
3675 
3676 #undef __FUNCT__
3677 #define __FUNCT__ "DMPlexShiftLabels_Private"
3678 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3679 {
3680   PetscSF            sfPoint;
3681   DMLabel            vtkLabel, ghostLabel;
3682   PetscInt          *depthEnd;
3683   const PetscSFNode *leafRemote;
3684   const PetscInt    *leafLocal;
3685   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3686   PetscMPIInt        rank;
3687   PetscErrorCode     ierr;
3688 
3689   PetscFunctionBegin;
3690   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3691   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3692   for (d = 0; d <= depth; ++d) {
3693     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3694   }
3695   /* Step 10: Convert labels */
3696   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3697   for (l = 0; l < numLabels; ++l) {
3698     DMLabel         label, newlabel;
3699     const char     *lname;
3700     PetscBool       isDepth;
3701     IS              valueIS;
3702     const PetscInt *values;
3703     PetscInt        numValues, val;
3704 
3705     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3706     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3707     if (isDepth) continue;
3708     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3709     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3710     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3711     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3712     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3713     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3714     for (val = 0; val < numValues; ++val) {
3715       IS              pointIS;
3716       const PetscInt *points;
3717       PetscInt        numPoints, p;
3718 
3719       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3720       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3721       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3722       for (p = 0; p < numPoints; ++p) {
3723         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3724 
3725         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3726       }
3727       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3728       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3729     }
3730     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3731     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3732   }
3733   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3734   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3735   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3736   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3737   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3738   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3739   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3740   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3741   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3742   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3743   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3744     for (; c < leafLocal[l] && c < cEnd; ++c) {
3745       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3746     }
3747     if (leafLocal[l] >= cEnd) break;
3748     if (leafRemote[l].rank == rank) {
3749       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3750     } else {
3751       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3752     }
3753   }
3754   for (; c < cEnd; ++c) {
3755     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3756   }
3757   if (0) {
3758     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3759     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3760     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3761   }
3762   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3763   for (f = fStart; f < fEnd; ++f) {
3764     PetscInt numCells;
3765 
3766     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3767     if (numCells < 2) {
3768       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3769     } else {
3770       const PetscInt *cells = NULL;
3771       PetscInt        vA, vB;
3772 
3773       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3774       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3775       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3776       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3777     }
3778   }
3779   if (0) {
3780     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3781     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3782     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3783   }
3784   PetscFunctionReturn(0);
3785 }
3786 
3787 #undef __FUNCT__
3788 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3789 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3790 {
3791   DMLabel         label;
3792   IS              valueIS;
3793   const PetscInt *values;
3794   PetscInt       *depthShift;
3795   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3796   PetscErrorCode  ierr;
3797 
3798   PetscFunctionBegin;
3799   /* Count ghost cells */
3800   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3801   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3802   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3803   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3804 
3805   *numGhostCells = 0;
3806   for (fs = 0; fs < numFS; ++fs) {
3807     PetscInt numBdFaces;
3808 
3809     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3810 
3811     *numGhostCells += numBdFaces;
3812   }
3813   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3814   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3815   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3816   if (depth >= 0) depthShift[depth] = *numGhostCells;
3817   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3818   /* Step 3: Set cone/support sizes for new points */
3819   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3820   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3821     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3822   }
3823   for (fs = 0; fs < numFS; ++fs) {
3824     IS              faceIS;
3825     const PetscInt *faces;
3826     PetscInt        numFaces, f;
3827 
3828     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3829     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3830     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3831     for (f = 0; f < numFaces; ++f) {
3832       PetscInt size;
3833 
3834       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3835       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3836       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   /* Step 4: Setup ghosted DM */
3842   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3843   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3844   /* Step 6: Set cones and supports for new points */
3845   ghostCell = cEnd;
3846   for (fs = 0; fs < numFS; ++fs) {
3847     IS              faceIS;
3848     const PetscInt *faces;
3849     PetscInt        numFaces, f;
3850 
3851     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3852     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3853     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3854     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3855       PetscInt newFace = faces[f] + *numGhostCells;
3856 
3857       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3858       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3859     }
3860     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3861     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3862   }
3863   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3864   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3865   /* Step 7: Stratify */
3866   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3867   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3868   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3869   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3870   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3871   PetscFunctionReturn(0);
3872 }
3873 
3874 #undef __FUNCT__
3875 #define __FUNCT__ "DMPlexConstructGhostCells"
3876 /*@C
3877   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3878 
3879   Collective on dm
3880 
3881   Input Parameters:
3882 + dm - The original DM
3883 - labelName - The label specifying the boundary faces (this could be auto-generated)
3884 
3885   Output Parameters:
3886 + numGhostCells - The number of ghost cells added to the DM
3887 - dmGhosted - The new DM
3888 
3889   Level: developer
3890 
3891 .seealso: DMCreate()
3892 */
3893 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3894 {
3895   DM             gdm;
3896   PetscInt       dim;
3897   PetscErrorCode ierr;
3898 
3899   PetscFunctionBegin;
3900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3901   PetscValidPointer(numGhostCells, 3);
3902   PetscValidPointer(dmGhosted, 4);
3903   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3904   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3906   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3907   switch (dim) {
3908   case 2:
3909     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3910     break;
3911   default:
3912     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3913   }
3914   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3915   *dmGhosted = gdm;
3916   PetscFunctionReturn(0);
3917 }
3918 
3919 #undef __FUNCT__
3920 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3921 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3922 {
3923   MPI_Comm        comm;
3924   IS              valueIS, *pointIS;
3925   const PetscInt *values, **splitPoints;
3926   PetscSection    coordSection;
3927   Vec             coordinates;
3928   PetscScalar    *coords;
3929   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3930   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3931   PetscErrorCode  ierr;
3932 
3933   PetscFunctionBegin;
3934   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3935   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3936   /* Count split points and add cohesive cells */
3937   if (label) {
3938     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3939     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3940     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3941   }
3942   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3943   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3944   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3945   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3946   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3947   for (d = 0; d <= depth; ++d) {
3948     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3949     numSplitPoints[d] = 0;
3950     splitPoints[d]    = NULL;
3951     pointIS[d]        = NULL;
3952   }
3953   for (sp = 0; sp < numSP; ++sp) {
3954     const PetscInt dep = values[sp];
3955 
3956     if ((dep < 0) || (dep > depth)) continue;
3957     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3958     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3959     if (pointIS[dep]) {
3960       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3961       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3962     }
3963   }
3964   if (depth >= 0) {
3965     /* Calculate number of additional points */
3966     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3967     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3968     /* Calculate hybrid bound for each dimension */
3969     pMaxNew[0] += depthShift[depth];
3970     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3971     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3972 
3973     /* Calculate point offset for each dimension */
3974     depthOffset[depth] = 0;
3975     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3976     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3977     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3978   }
3979   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3980   /* Step 3: Set cone/support sizes for new points */
3981   for (dep = 0; dep <= depth; ++dep) {
3982     for (p = 0; p < numSplitPoints[dep]; ++p) {
3983       const PetscInt  oldp   = splitPoints[dep][p];
3984       const PetscInt  newp   = depthOffset[dep] + oldp;
3985       const PetscInt  splitp = pMaxNew[dep] + p;
3986       const PetscInt *support;
3987       PetscInt        coneSize, supportSize, q, e;
3988 
3989       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3990       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3991       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3992       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3993       if (dep == depth-1) {
3994         const PetscInt ccell = pMaxNew[depth] + p;
3995         /* Add cohesive cells, they are prisms */
3996         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3997       } else if (dep == 0) {
3998         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3999 
4000         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4001         /* Split old vertex: Edges in old split faces and new cohesive edge */
4002         for (e = 0, q = 0; e < supportSize; ++e) {
4003           PetscInt val;
4004 
4005           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4006           if ((val == 1) || (val == (shift + 1))) ++q;
4007         }
4008         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4009         /* Split new vertex: Edges in new split faces and new cohesive edge */
4010         for (e = 0, q = 0; e < supportSize; ++e) {
4011           PetscInt val;
4012 
4013           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4014           if ((val == 1) || (val == -(shift + 1))) ++q;
4015         }
4016         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4017         /* Add cohesive edges */
4018         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4019         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4020       } else if (dep == dim-2) {
4021         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4022         /* Split old edge: Faces in positive side cells and old split faces */
4023         for (e = 0, q = 0; e < supportSize; ++e) {
4024           PetscInt val;
4025 
4026           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4027           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4028         }
4029         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4030         /* Split new edge: Faces in negative side cells and new split faces */
4031         for (e = 0, q = 0; e < supportSize; ++e) {
4032           PetscInt val;
4033 
4034           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4035           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4036         }
4037         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4038       }
4039     }
4040   }
4041   /* Step 4: Setup split DM */
4042   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4043   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4044   /* Step 6: Set cones and supports for new points */
4045   for (dep = 0; dep <= depth; ++dep) {
4046     for (p = 0; p < numSplitPoints[dep]; ++p) {
4047       const PetscInt  oldp   = splitPoints[dep][p];
4048       const PetscInt  newp   = depthOffset[dep] + oldp;
4049       const PetscInt  splitp = pMaxNew[dep] + p;
4050       const PetscInt *cone, *support, *ornt;
4051       PetscInt        coneSize, supportSize, q, v, e, s;
4052 
4053       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4054       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4055       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4056       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4057       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4058       if (dep == depth-1) {
4059         const PetscInt  ccell = pMaxNew[depth] + p;
4060         const PetscInt *supportF;
4061 
4062         /* Split face:       copy in old face to new face to start */
4063         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4064         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4065         /* Split old face:   old vertices/edges in cone so no change */
4066         /* Split new face:   new vertices/edges in cone */
4067         for (q = 0; q < coneSize; ++q) {
4068           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4069 
4070           coneNew[2+q] = pMaxNew[dim-2] + v;
4071         }
4072         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4073         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4074         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4075         coneNew[0] = newp;
4076         coneNew[1] = splitp;
4077         for (q = 0; q < coneSize; ++q) {
4078           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4079         }
4080         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4081 
4082 
4083         for (s = 0; s < supportSize; ++s) {
4084           PetscInt val;
4085 
4086           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4087           if (val < 0) {
4088             /* Split old face:   Replace negative side cell with cohesive cell */
4089             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4090           } else {
4091             /* Split new face:   Replace positive side cell with cohesive cell */
4092             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4093           }
4094         }
4095       } else if (dep == 0) {
4096         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4097 
4098         /* Split old vertex: Edges in old split faces and new cohesive edge */
4099         for (e = 0, q = 0; e < supportSize; ++e) {
4100           PetscInt val;
4101 
4102           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4103           if ((val == 1) || (val == (shift + 1))) {
4104             supportNew[q++] = depthOffset[1] + support[e];
4105           }
4106         }
4107         supportNew[q] = cedge;
4108 
4109         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4110         /* Split new vertex: Edges in new split faces and new cohesive edge */
4111         for (e = 0, q = 0; e < supportSize; ++e) {
4112           PetscInt val, edge;
4113 
4114           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4115           if (val == 1) {
4116             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4117             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4118             supportNew[q++] = pMaxNew[1] + edge;
4119           } else if (val == -(shift + 1)) {
4120             supportNew[q++] = depthOffset[1] + support[e];
4121           }
4122         }
4123         supportNew[q] = cedge;
4124         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4125         /* Cohesive edge:    Old and new split vertex, punting on support */
4126         coneNew[0] = newp;
4127         coneNew[1] = splitp;
4128         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4129       } else if (dep == dim-2) {
4130         /* Split old edge:   old vertices in cone so no change */
4131         /* Split new edge:   new vertices in cone */
4132         for (q = 0; q < coneSize; ++q) {
4133           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4134 
4135           coneNew[q] = pMaxNew[dim-3] + v;
4136         }
4137         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4138         /* Split old edge: Faces in positive side cells and old split faces */
4139         for (e = 0, q = 0; e < supportSize; ++e) {
4140           PetscInt val;
4141 
4142           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4143           if ((val == dim-1) || (val == (shift + dim-1))) {
4144             supportNew[q++] = depthOffset[dim-1] + support[e];
4145           }
4146         }
4147         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4148         /* Split new edge: Faces in negative side cells and new split faces */
4149         for (e = 0, q = 0; e < supportSize; ++e) {
4150           PetscInt val, face;
4151 
4152           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4153           if (val == dim-1) {
4154             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4155             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4156             supportNew[q++] = pMaxNew[dim-1] + face;
4157           } else if (val == -(shift + dim-1)) {
4158             supportNew[q++] = depthOffset[dim-1] + support[e];
4159           }
4160         }
4161         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4162       }
4163     }
4164   }
4165   /* Step 6b: Replace split points in negative side cones */
4166   for (sp = 0; sp < numSP; ++sp) {
4167     PetscInt        dep = values[sp];
4168     IS              pIS;
4169     PetscInt        numPoints;
4170     const PetscInt *points;
4171 
4172     if (dep >= 0) continue;
4173     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4174     if (!pIS) continue;
4175     dep  = -dep - shift;
4176     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4177     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4178     for (p = 0; p < numPoints; ++p) {
4179       const PetscInt  oldp = points[p];
4180       const PetscInt  newp = depthOffset[dep] + oldp;
4181       const PetscInt *cone;
4182       PetscInt        coneSize, c;
4183       PetscBool       replaced = PETSC_FALSE;
4184 
4185       /* Negative edge: replace split vertex */
4186       /* Negative cell: replace split face */
4187       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4188       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4189       for (c = 0; c < coneSize; ++c) {
4190         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4191         PetscInt       csplitp, cp, val;
4192 
4193         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4194         if (val == dep-1) {
4195           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4196           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4197           csplitp  = pMaxNew[dep-1] + cp;
4198           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4199           replaced = PETSC_TRUE;
4200         }
4201       }
4202       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4203     }
4204     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4205     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4206   }
4207   /* Step 7: Stratify */
4208   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4209   /* Step 8: Coordinates */
4210   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4211   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4212   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4213   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4214   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4215     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4216     const PetscInt splitp = pMaxNew[0] + v;
4217     PetscInt       dof, off, soff, d;
4218 
4219     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4220     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4221     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4222     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4223   }
4224   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4225   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4226   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4227   /* Step 10: Labels */
4228   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4229   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4230   for (dep = 0; dep <= depth; ++dep) {
4231     for (p = 0; p < numSplitPoints[dep]; ++p) {
4232       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4233       const PetscInt splitp = pMaxNew[dep] + p;
4234       PetscInt       l;
4235 
4236       for (l = 0; l < numLabels; ++l) {
4237         DMLabel     mlabel;
4238         const char *lname;
4239         PetscInt    val;
4240 
4241         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4242         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4243         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4244         if (val >= 0) {
4245           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4246           if (dep == 0) {
4247             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4248             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4249           }
4250         }
4251       }
4252     }
4253   }
4254   for (sp = 0; sp < numSP; ++sp) {
4255     const PetscInt dep = values[sp];
4256 
4257     if ((dep < 0) || (dep > depth)) continue;
4258     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4259     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4260   }
4261   if (label) {
4262     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4263     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4264   }
4265   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4266   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4267   PetscFunctionReturn(0);
4268 }
4269 
4270 #undef __FUNCT__
4271 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4272 /*@C
4273   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4274 
4275   Collective on dm
4276 
4277   Input Parameters:
4278 + dm - The original DM
4279 - labelName - The label specifying the boundary faces (this could be auto-generated)
4280 
4281   Output Parameters:
4282 - dmSplit - The new DM
4283 
4284   Level: developer
4285 
4286 .seealso: DMCreate()
4287 */
4288 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4289 {
4290   DM             sdm;
4291   PetscInt       dim;
4292   PetscErrorCode ierr;
4293 
4294   PetscFunctionBegin;
4295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4296   PetscValidPointer(dmSplit, 4);
4297   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4298   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4299   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4300   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4301   switch (dim) {
4302   case 2:
4303   case 3:
4304     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4305     break;
4306   default:
4307     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4308   }
4309   *dmSplit = sdm;
4310   PetscFunctionReturn(0);
4311 }
4312 
4313 #undef __FUNCT__
4314 #define __FUNCT__ "DMLabelCohesiveComplete"
4315 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4316 {
4317   IS              dimIS;
4318   const PetscInt *points;
4319   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4320   PetscErrorCode  ierr;
4321 
4322   PetscFunctionBegin;
4323   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4324   /* Cell orientation for face gives the side of the fault */
4325   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4326   if (!dimIS) PetscFunctionReturn(0);
4327   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4328   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4329   for (p = 0; p < numPoints; ++p) {
4330     const PetscInt *support;
4331     PetscInt        supportSize, s;
4332 
4333     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4334     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4335     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4336     for (s = 0; s < supportSize; ++s) {
4337       const PetscInt *cone, *ornt;
4338       PetscInt        coneSize, c;
4339       PetscBool       pos = PETSC_TRUE;
4340 
4341       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4342       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4343       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4344       for (c = 0; c < coneSize; ++c) {
4345         if (cone[c] == points[p]) {
4346           if (ornt[c] >= 0) {
4347             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4348           } else {
4349             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4350             pos  = PETSC_FALSE;
4351           }
4352           break;
4353         }
4354       }
4355       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4356       /* Put faces touching the fault in the label */
4357       for (c = 0; c < coneSize; ++c) {
4358         const PetscInt point = cone[c];
4359 
4360         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4361         if (val == -1) {
4362           PetscInt *closure = NULL;
4363           PetscInt  closureSize, cl;
4364 
4365           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4366           for (cl = 0; cl < closureSize*2; cl += 2) {
4367             const PetscInt clp = closure[cl];
4368 
4369             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4370             if ((val >= 0) && (val < dim-1)) {
4371               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4372               break;
4373             }
4374           }
4375           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4376         }
4377       }
4378     }
4379   }
4380   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4381   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4382   /* Search for other cells/faces/edges connected to the fault by a vertex */
4383   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4384   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4385   if (!dimIS) PetscFunctionReturn(0);
4386   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4387   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4388   for (p = 0; p < numPoints; ++p) {
4389     PetscInt *star = NULL;
4390     PetscInt  starSize, s;
4391     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4392 
4393     /* First mark cells connected to the fault */
4394     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4395     while (again) {
4396       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4397       again = 0;
4398       for (s = 0; s < starSize*2; s += 2) {
4399         const PetscInt  point = star[s];
4400         const PetscInt *cone;
4401         PetscInt        coneSize, c;
4402 
4403         if ((point < cStart) || (point >= cEnd)) continue;
4404         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4405         if (val != -1) continue;
4406         again = 2;
4407         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4408         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4409         for (c = 0; c < coneSize; ++c) {
4410           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4411           if (val != -1) {
4412             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4413             if (val > 0) {
4414               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4415             } else {
4416               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4417             }
4418             again = 1;
4419             break;
4420           }
4421         }
4422       }
4423     }
4424     /* Classify the rest by cell membership */
4425     for (s = 0; s < starSize*2; s += 2) {
4426       const PetscInt point = star[s];
4427 
4428       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4429       if (val == -1) {
4430         PetscInt  *sstar = NULL;
4431         PetscInt   sstarSize, ss;
4432         PetscBool  marked = PETSC_FALSE;
4433 
4434         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4435         for (ss = 0; ss < sstarSize*2; ss += 2) {
4436           const PetscInt spoint = sstar[ss];
4437 
4438           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4439           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4440           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4441           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4442           if (val > 0) {
4443             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4444           } else {
4445             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4446           }
4447           marked = PETSC_TRUE;
4448           break;
4449         }
4450         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4451         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4452       }
4453     }
4454     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4455   }
4456   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4457   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4458   PetscFunctionReturn(0);
4459 }
4460 
4461 #undef __FUNCT__
4462 #define __FUNCT__ "DMPlexInterpolate_2D"
4463 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4464 {
4465   DM             idm;
4466   DM_Plex       *mesh;
4467   PetscHashIJ    edgeTable;
4468   PetscInt      *off;
4469   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4470   PetscInt       numEdges, firstEdge, edge, e;
4471   PetscErrorCode ierr;
4472 
4473   PetscFunctionBegin;
4474   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4475   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4476   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4477   numCells    = cEnd - cStart;
4478   numVertices = vEnd - vStart;
4479   firstEdge   = numCells + numVertices;
4480   numEdges    = 0;
4481   /* Count edges using algorithm from CreateNeighborCSR */
4482   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4483   if (off) {
4484     PetscInt numCorners = 0;
4485 
4486     numEdges = off[numCells]/2;
4487 #if 0
4488     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4489     numEdges += 3*numCells - off[numCells];
4490 #else
4491     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4492     for (c = cStart; c < cEnd; ++c) {
4493       PetscInt coneSize;
4494 
4495       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4496       numCorners += coneSize;
4497     }
4498     numEdges += numCorners - off[numCells];
4499 #endif
4500   }
4501 #if 0
4502   /* Check Euler characteristic V - E + F = 1 */
4503   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4504 #endif
4505   /* Create interpolated mesh */
4506   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4507   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4508   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4509   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4510   for (c = 0; c < numCells; ++c) {
4511     PetscInt numCorners;
4512 
4513     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4514     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4515   }
4516   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4517     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4518   }
4519   ierr = DMSetUp(idm);CHKERRQ(ierr);
4520   /* Get edge cones from subsets of cell vertices */
4521   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4522   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4523 
4524   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4525     const PetscInt *cellFaces;
4526     PetscInt        numCellFaces, faceSize, cf;
4527 
4528     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4529     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4530     for (cf = 0; cf < numCellFaces; ++cf) {
4531 #if 1
4532       PetscHashIJKey key;
4533 
4534       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4535       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4536       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4537       if (e < 0) {
4538         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4539         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4540         e    = edge++;
4541       }
4542 #else
4543       PetscBool found = PETSC_FALSE;
4544 
4545       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4546       for (e = firstEdge; e < edge; ++e) {
4547         const PetscInt *cone;
4548 
4549         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4550         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4551             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4552           found = PETSC_TRUE;
4553           break;
4554         }
4555       }
4556       if (!found) {
4557         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4558         ++edge;
4559       }
4560 #endif
4561       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4562     }
4563   }
4564   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4565   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4566   ierr = PetscFree(off);CHKERRQ(ierr);
4567   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4568   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4569   mesh = (DM_Plex*) (idm)->data;
4570   /* Orient edges */
4571   for (c = 0; c < numCells; ++c) {
4572     const PetscInt *cone = NULL, *cellFaces;
4573     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4574 
4575     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4576     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4577     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4578     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4579     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4580     for (cf = 0; cf < numCellFaces; ++cf) {
4581       const PetscInt *econe = NULL;
4582       PetscInt        esize;
4583 
4584       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4585       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4586       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4587       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4588         /* Correctly oriented */
4589         mesh->coneOrientations[coff+cf] = 0;
4590       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4591         /* Start at index 1, and reverse orientation */
4592         mesh->coneOrientations[coff+cf] = -(1+1);
4593       }
4594     }
4595   }
4596   *dmInt = idm;
4597   PetscFunctionReturn(0);
4598 }
4599 
4600 #undef __FUNCT__
4601 #define __FUNCT__ "DMPlexInterpolate_3D"
4602 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4603 {
4604   DM             idm, fdm;
4605   DM_Plex       *mesh;
4606   PetscInt      *off;
4607   const PetscInt numCorners = 4;
4608   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4609   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4610   PetscErrorCode ierr;
4611 
4612   PetscFunctionBegin;
4613   {
4614     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4615     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4616     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4617   }
4618   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4619   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4620   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4621   numCells    = cEnd - cStart;
4622   numVertices = vEnd - vStart;
4623   firstFace   = numCells + numVertices;
4624   numFaces    = 0;
4625   /* Count faces using algorithm from CreateNeighborCSR */
4626   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4627   if (off) {
4628     numFaces = off[numCells]/2;
4629     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4630     numFaces += 4*numCells - off[numCells];
4631   }
4632   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4633   firstEdge = firstFace + numFaces;
4634   numEdges  = numVertices + numFaces - numCells - 1;
4635   /* Create interpolated mesh */
4636   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4637   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4638   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4639   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4640   for (c = 0; c < numCells; ++c) {
4641     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4642   }
4643   for (f = firstFace; f < firstFace+numFaces; ++f) {
4644     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4645   }
4646   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4647     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4648   }
4649   ierr = DMSetUp(idm);CHKERRQ(ierr);
4650   /* Get face cones from subsets of cell vertices */
4651   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &fdm);CHKERRQ(ierr);
4652   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4653   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4654   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4655   for (f = firstFace; f < firstFace+numFaces; ++f) {
4656     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4657   }
4658   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4659   for (c = 0, face = firstFace; c < numCells; ++c) {
4660     const PetscInt *cellFaces;
4661     PetscInt        numCellFaces, faceSize, cf;
4662 
4663     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4664     if (faceSize != 3) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4665     for (cf = 0; cf < numCellFaces; ++cf) {
4666       PetscBool found = PETSC_FALSE;
4667 
4668       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4669       for (f = firstFace; f < face; ++f) {
4670         const PetscInt *cone = NULL;
4671 
4672         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4673         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4674             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4675             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4676             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4677             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4678             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4679           found = PETSC_TRUE;
4680           break;
4681         }
4682       }
4683       if (!found) {
4684         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4685         /* Save the vertices for orientation calculation */
4686         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4687         ++face;
4688       }
4689       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4690     }
4691   }
4692   if (face != firstFace+numFaces) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4693   /* Get edge cones from subsets of face vertices */
4694   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4695     const PetscInt *cellFaces;
4696     PetscInt        numCellFaces, faceSize, cf;
4697 
4698     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4699     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4700     for (cf = 0; cf < numCellFaces; ++cf) {
4701       PetscBool found = PETSC_FALSE;
4702 
4703       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4704       for (e = firstEdge; e < edge; ++e) {
4705         const PetscInt *cone = NULL;
4706 
4707         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4708         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4709             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4710           found = PETSC_TRUE;
4711           break;
4712         }
4713       }
4714       if (!found) {
4715         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4716         ++edge;
4717       }
4718       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4719     }
4720   }
4721   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4722   ierr = PetscFree(off);CHKERRQ(ierr);
4723   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4724   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4725   mesh = (DM_Plex*) (idm)->data;
4726   /* Orient edges */
4727   for (f = firstFace; f < firstFace+numFaces; ++f) {
4728     const PetscInt *cone, *cellFaces;
4729     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4730 
4731     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4732     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4733     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4734     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4735     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4736     for (cf = 0; cf < numCellFaces; ++cf) {
4737       const PetscInt *econe;
4738       PetscInt        esize;
4739 
4740       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4741       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4742       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4743       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4744         /* Correctly oriented */
4745         mesh->coneOrientations[coff+cf] = 0;
4746       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4747         /* Start at index 1, and reverse orientation */
4748         mesh->coneOrientations[coff+cf] = -(1+1);
4749       }
4750     }
4751   }
4752   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4753   /* Orient faces */
4754   for (c = 0; c < numCells; ++c) {
4755     const PetscInt *cone, *cellFaces;
4756     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4757 
4758     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4759     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4760     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4761     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4762     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4763     for (cf = 0; cf < numCellFaces; ++cf) {
4764       PetscInt *origClosure = NULL, *closure;
4765       PetscInt closureSize, i;
4766 
4767       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4768       if (closureSize != 7) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4769       for (i = 4; i < 7; ++i) {
4770         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4771       }
4772       closure = &origClosure[4*2];
4773       /* Remember that this is the orientation for edges, not vertices */
4774       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4775         /* Correctly oriented */
4776         mesh->coneOrientations[coff+cf] = 0;
4777       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4778         /* Shifted by 1 */
4779         mesh->coneOrientations[coff+cf] = 1;
4780       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4781         /* Shifted by 2 */
4782         mesh->coneOrientations[coff+cf] = 2;
4783       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4784         /* Start at edge 1, and reverse orientation */
4785         mesh->coneOrientations[coff+cf] = -(1+1);
4786       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4787         /* Start at index 0, and reverse orientation */
4788         mesh->coneOrientations[coff+cf] = -(0+1);
4789       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4790         /* Start at index 2, and reverse orientation */
4791         mesh->coneOrientations[coff+cf] = -(2+1);
4792       } else SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4793       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4794     }
4795   }
4796   {
4797     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4798     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4799     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4800   }
4801   *dmInt = idm;
4802   PetscFunctionReturn(0);
4803 }
4804 
4805 #undef __FUNCT__
4806 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4807 /*
4808   This takes as input the common mesh generator output, a list of the vertices for each cell
4809 */
4810 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4811 {
4812   PetscInt      *cone, c, p;
4813   PetscErrorCode ierr;
4814 
4815   PetscFunctionBegin;
4816   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4817   for (c = 0; c < numCells; ++c) {
4818     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4819   }
4820   ierr = DMSetUp(dm);CHKERRQ(ierr);
4821   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4822   for (c = 0; c < numCells; ++c) {
4823     for (p = 0; p < numCorners; ++p) {
4824       cone[p] = cells[c*numCorners+p]+numCells;
4825     }
4826     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4827   }
4828   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4829   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4830   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4831   PetscFunctionReturn(0);
4832 }
4833 
4834 #undef __FUNCT__
4835 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4836 /*
4837   This takes as input the coordinates for each vertex
4838 */
4839 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4840 {
4841   PetscSection   coordSection;
4842   Vec            coordinates;
4843   PetscScalar   *coords;
4844   PetscInt       coordSize, v, d;
4845   PetscErrorCode ierr;
4846 
4847   PetscFunctionBegin;
4848   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4849   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4850   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4851   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4852   for (v = numCells; v < numCells+numVertices; ++v) {
4853     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4854     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4855   }
4856   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4857   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4858   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4859   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4860   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4861   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4862   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4863   for (v = 0; v < numVertices; ++v) {
4864     for (d = 0; d < spaceDim; ++d) {
4865       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4866     }
4867   }
4868   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4869   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4870   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4871   PetscFunctionReturn(0);
4872 }
4873 
4874 #undef __FUNCT__
4875 #define __FUNCT__ "DMPlexCreateFromCellList"
4876 /*
4877   This takes as input the common mesh generator output, a list of the vertices for each cell
4878 */
4879 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4880 {
4881   PetscErrorCode ierr;
4882 
4883   PetscFunctionBegin;
4884   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4885   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4886   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4887   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4888   if (interpolate) {
4889     DM idm;
4890 
4891     switch (dim) {
4892     case 2:
4893       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4894     case 3:
4895       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4896     default:
4897       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4898     }
4899     ierr = DMDestroy(dm);CHKERRQ(ierr);
4900     *dm  = idm;
4901   }
4902   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4903   PetscFunctionReturn(0);
4904 }
4905 
4906 #if defined(PETSC_HAVE_TRIANGLE)
4907 #include <triangle.h>
4908 
4909 #undef __FUNCT__
4910 #define __FUNCT__ "InitInput_Triangle"
4911 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4912 {
4913   PetscFunctionBegin;
4914   inputCtx->numberofpoints             = 0;
4915   inputCtx->numberofpointattributes    = 0;
4916   inputCtx->pointlist                  = NULL;
4917   inputCtx->pointattributelist         = NULL;
4918   inputCtx->pointmarkerlist            = NULL;
4919   inputCtx->numberofsegments           = 0;
4920   inputCtx->segmentlist                = NULL;
4921   inputCtx->segmentmarkerlist          = NULL;
4922   inputCtx->numberoftriangleattributes = 0;
4923   inputCtx->trianglelist               = NULL;
4924   inputCtx->numberofholes              = 0;
4925   inputCtx->holelist                   = NULL;
4926   inputCtx->numberofregions            = 0;
4927   inputCtx->regionlist                 = NULL;
4928   PetscFunctionReturn(0);
4929 }
4930 
4931 #undef __FUNCT__
4932 #define __FUNCT__ "InitOutput_Triangle"
4933 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4934 {
4935   PetscFunctionBegin;
4936   outputCtx->numberofpoints        = 0;
4937   outputCtx->pointlist             = NULL;
4938   outputCtx->pointattributelist    = NULL;
4939   outputCtx->pointmarkerlist       = NULL;
4940   outputCtx->numberoftriangles     = 0;
4941   outputCtx->trianglelist          = NULL;
4942   outputCtx->triangleattributelist = NULL;
4943   outputCtx->neighborlist          = NULL;
4944   outputCtx->segmentlist           = NULL;
4945   outputCtx->segmentmarkerlist     = NULL;
4946   outputCtx->numberofedges         = 0;
4947   outputCtx->edgelist              = NULL;
4948   outputCtx->edgemarkerlist        = NULL;
4949   PetscFunctionReturn(0);
4950 }
4951 
4952 #undef __FUNCT__
4953 #define __FUNCT__ "FiniOutput_Triangle"
4954 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4955 {
4956   PetscFunctionBegin;
4957   free(outputCtx->pointmarkerlist);
4958   free(outputCtx->edgelist);
4959   free(outputCtx->edgemarkerlist);
4960   free(outputCtx->trianglelist);
4961   free(outputCtx->neighborlist);
4962   PetscFunctionReturn(0);
4963 }
4964 
4965 #undef __FUNCT__
4966 #define __FUNCT__ "DMPlexGenerate_Triangle"
4967 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4968 {
4969   MPI_Comm             comm;
4970   PetscInt             dim              = 2;
4971   const PetscBool      createConvexHull = PETSC_FALSE;
4972   const PetscBool      constrained      = PETSC_FALSE;
4973   struct triangulateio in;
4974   struct triangulateio out;
4975   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4976   PetscMPIInt          rank;
4977   PetscErrorCode       ierr;
4978 
4979   PetscFunctionBegin;
4980   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4981   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4982   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4983   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4984   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4985 
4986   in.numberofpoints = vEnd - vStart;
4987   if (in.numberofpoints > 0) {
4988     PetscSection coordSection;
4989     Vec          coordinates;
4990     PetscScalar *array;
4991 
4992     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4993     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4994     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4995     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4996     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4997     for (v = vStart; v < vEnd; ++v) {
4998       const PetscInt idx = v - vStart;
4999       PetscInt       off, d;
5000 
5001       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5002       for (d = 0; d < dim; ++d) {
5003         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5004       }
5005       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5006     }
5007     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5008   }
5009   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5010   in.numberofsegments = eEnd - eStart;
5011   if (in.numberofsegments > 0) {
5012     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5013     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5014     for (e = eStart; e < eEnd; ++e) {
5015       const PetscInt  idx = e - eStart;
5016       const PetscInt *cone;
5017 
5018       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5019 
5020       in.segmentlist[idx*2+0] = cone[0] - vStart;
5021       in.segmentlist[idx*2+1] = cone[1] - vStart;
5022 
5023       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5024     }
5025   }
5026 #if 0 /* Do not currently support holes */
5027   PetscReal *holeCoords;
5028   PetscInt   h, d;
5029 
5030   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5031   if (in.numberofholes > 0) {
5032     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5033     for (h = 0; h < in.numberofholes; ++h) {
5034       for (d = 0; d < dim; ++d) {
5035         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5036       }
5037     }
5038   }
5039 #endif
5040   if (!rank) {
5041     char args[32];
5042 
5043     /* Take away 'Q' for verbose output */
5044     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5045     if (createConvexHull) {
5046       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5047     }
5048     if (constrained) {
5049       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5050     }
5051     triangulate(args, &in, &out, NULL);
5052   }
5053   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5054   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5055   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5056   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5057   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5058 
5059   {
5060     const PetscInt numCorners  = 3;
5061     const PetscInt numCells    = out.numberoftriangles;
5062     const PetscInt numVertices = out.numberofpoints;
5063     const int     *cells      = out.trianglelist;
5064     const double  *meshCoords = out.pointlist;
5065 
5066     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5067     /* Set labels */
5068     for (v = 0; v < numVertices; ++v) {
5069       if (out.pointmarkerlist[v]) {
5070         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5071       }
5072     }
5073     if (interpolate) {
5074       for (e = 0; e < out.numberofedges; e++) {
5075         if (out.edgemarkerlist[e]) {
5076           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5077           const PetscInt *edges;
5078           PetscInt        numEdges;
5079 
5080           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5081           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5082           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5083           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5084         }
5085       }
5086     }
5087     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5088   }
5089 #if 0 /* Do not currently support holes */
5090   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5091 #endif
5092   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5093   PetscFunctionReturn(0);
5094 }
5095 
5096 #undef __FUNCT__
5097 #define __FUNCT__ "DMPlexRefine_Triangle"
5098 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5099 {
5100   MPI_Comm             comm;
5101   PetscInt             dim  = 2;
5102   struct triangulateio in;
5103   struct triangulateio out;
5104   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5105   PetscMPIInt          rank;
5106   PetscErrorCode       ierr;
5107 
5108   PetscFunctionBegin;
5109   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5110   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5111   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5112   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5113   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5114   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5115   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5116 
5117   in.numberofpoints = vEnd - vStart;
5118   if (in.numberofpoints > 0) {
5119     PetscSection coordSection;
5120     Vec          coordinates;
5121     PetscScalar *array;
5122 
5123     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5124     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5125     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5126     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5127     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5128     for (v = vStart; v < vEnd; ++v) {
5129       const PetscInt idx = v - vStart;
5130       PetscInt       off, d;
5131 
5132       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5133       for (d = 0; d < dim; ++d) {
5134         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5135       }
5136       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5137     }
5138     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5139   }
5140   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5141 
5142   in.numberofcorners   = 3;
5143   in.numberoftriangles = cEnd - cStart;
5144 
5145   in.trianglearealist  = (double*) maxVolumes;
5146   if (in.numberoftriangles > 0) {
5147     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5148     for (c = cStart; c < cEnd; ++c) {
5149       const PetscInt idx      = c - cStart;
5150       PetscInt      *closure = NULL;
5151       PetscInt       closureSize;
5152 
5153       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5154       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5155       for (v = 0; v < 3; ++v) {
5156         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5157       }
5158       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5159     }
5160   }
5161   /* TODO: Segment markers are missing on input */
5162 #if 0 /* Do not currently support holes */
5163   PetscReal *holeCoords;
5164   PetscInt   h, d;
5165 
5166   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5167   if (in.numberofholes > 0) {
5168     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5169     for (h = 0; h < in.numberofholes; ++h) {
5170       for (d = 0; d < dim; ++d) {
5171         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5172       }
5173     }
5174   }
5175 #endif
5176   if (!rank) {
5177     char args[32];
5178 
5179     /* Take away 'Q' for verbose output */
5180     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5181     triangulate(args, &in, &out, NULL);
5182   }
5183   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5184   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5185   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5186   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5187   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5188 
5189   {
5190     const PetscInt numCorners  = 3;
5191     const PetscInt numCells    = out.numberoftriangles;
5192     const PetscInt numVertices = out.numberofpoints;
5193     const int     *cells      = out.trianglelist;
5194     const double  *meshCoords = out.pointlist;
5195     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5196 
5197     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5198     /* Set labels */
5199     for (v = 0; v < numVertices; ++v) {
5200       if (out.pointmarkerlist[v]) {
5201         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5202       }
5203     }
5204     if (interpolate) {
5205       PetscInt e;
5206 
5207       for (e = 0; e < out.numberofedges; e++) {
5208         if (out.edgemarkerlist[e]) {
5209           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5210           const PetscInt *edges;
5211           PetscInt        numEdges;
5212 
5213           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5214           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5215           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5216           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5217         }
5218       }
5219     }
5220     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5221   }
5222 #if 0 /* Do not currently support holes */
5223   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5224 #endif
5225   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5226   PetscFunctionReturn(0);
5227 }
5228 #endif
5229 
5230 #if defined(PETSC_HAVE_TETGEN)
5231 #include <tetgen.h>
5232 #undef __FUNCT__
5233 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5234 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5235 {
5236   MPI_Comm       comm;
5237   const PetscInt dim  = 3;
5238   ::tetgenio     in;
5239   ::tetgenio     out;
5240   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5241   PetscMPIInt    rank;
5242   PetscErrorCode ierr;
5243 
5244   PetscFunctionBegin;
5245   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5246   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5247   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5248   in.numberofpoints = vEnd - vStart;
5249   if (in.numberofpoints > 0) {
5250     PetscSection coordSection;
5251     Vec          coordinates;
5252     PetscScalar *array;
5253 
5254     in.pointlist       = new double[in.numberofpoints*dim];
5255     in.pointmarkerlist = new int[in.numberofpoints];
5256 
5257     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5258     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5259     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5260     for (v = vStart; v < vEnd; ++v) {
5261       const PetscInt idx = v - vStart;
5262       PetscInt       off, d;
5263 
5264       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5265       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5266       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5267     }
5268     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5269   }
5270   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5271 
5272   in.numberoffacets = fEnd - fStart;
5273   if (in.numberoffacets > 0) {
5274     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5275     in.facetmarkerlist = new int[in.numberoffacets];
5276     for (f = fStart; f < fEnd; ++f) {
5277       const PetscInt idx     = f - fStart;
5278       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
5279 
5280       in.facetlist[idx].numberofpolygons = 1;
5281       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5282       in.facetlist[idx].numberofholes    = 0;
5283       in.facetlist[idx].holelist         = NULL;
5284 
5285       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5286       for (p = 0; p < numPoints*2; p += 2) {
5287         const PetscInt point = points[p];
5288         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5289       }
5290 
5291       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5292       poly->numberofvertices = numVertices;
5293       poly->vertexlist       = new int[poly->numberofvertices];
5294       for (v = 0; v < numVertices; ++v) {
5295         const PetscInt vIdx = points[v] - vStart;
5296         poly->vertexlist[v] = vIdx;
5297       }
5298       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5299       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5300     }
5301   }
5302   if (!rank) {
5303     char args[32];
5304 
5305     /* Take away 'Q' for verbose output */
5306     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5307     ::tetrahedralize(args, &in, &out);
5308   }
5309   {
5310     const PetscInt numCorners  = 4;
5311     const PetscInt numCells    = out.numberoftetrahedra;
5312     const PetscInt numVertices = out.numberofpoints;
5313     const int     *cells      = out.tetrahedronlist;
5314     const double  *meshCoords = out.pointlist;
5315 
5316     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5317     /* Set labels */
5318     for (v = 0; v < numVertices; ++v) {
5319       if (out.pointmarkerlist[v]) {
5320         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5321       }
5322     }
5323     if (interpolate) {
5324       PetscInt e;
5325 
5326       for (e = 0; e < out.numberofedges; e++) {
5327         if (out.edgemarkerlist[e]) {
5328           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5329           const PetscInt *edges;
5330           PetscInt        numEdges;
5331 
5332           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5333           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5334           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5335           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5336         }
5337       }
5338       for (f = 0; f < out.numberoftrifaces; f++) {
5339         if (out.trifacemarkerlist[f]) {
5340           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5341           const PetscInt *faces;
5342           PetscInt        numFaces;
5343 
5344           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5345           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5346           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5347           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5348         }
5349       }
5350     }
5351     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5352   }
5353   PetscFunctionReturn(0);
5354 }
5355 
5356 #undef __FUNCT__
5357 #define __FUNCT__ "DMPlexRefine_Tetgen"
5358 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5359 {
5360   MPI_Comm       comm;
5361   const PetscInt dim  = 3;
5362   ::tetgenio     in;
5363   ::tetgenio     out;
5364   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5365   PetscMPIInt    rank;
5366   PetscErrorCode ierr;
5367 
5368   PetscFunctionBegin;
5369   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5370   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5371   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5372   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5373   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5374 
5375   in.numberofpoints = vEnd - vStart;
5376   if (in.numberofpoints > 0) {
5377     PetscSection coordSection;
5378     Vec          coordinates;
5379     PetscScalar *array;
5380 
5381     in.pointlist       = new double[in.numberofpoints*dim];
5382     in.pointmarkerlist = new int[in.numberofpoints];
5383 
5384     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5385     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5386     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5387     for (v = vStart; v < vEnd; ++v) {
5388       const PetscInt idx = v - vStart;
5389       PetscInt       off, d;
5390 
5391       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5392       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5393       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5394     }
5395     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5396   }
5397   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5398 
5399   in.numberofcorners       = 4;
5400   in.numberoftetrahedra    = cEnd - cStart;
5401   in.tetrahedronvolumelist = (double*) maxVolumes;
5402   if (in.numberoftetrahedra > 0) {
5403     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5404     for (c = cStart; c < cEnd; ++c) {
5405       const PetscInt idx      = c - cStart;
5406       PetscInt      *closure = NULL;
5407       PetscInt       closureSize;
5408 
5409       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5410       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5411       for (v = 0; v < 4; ++v) {
5412         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5413       }
5414       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5415     }
5416   }
5417   /* TODO: Put in boundary faces with markers */
5418   if (!rank) {
5419     char args[32];
5420 
5421     /* Take away 'Q' for verbose output */
5422     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5423     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5424     ::tetrahedralize(args, &in, &out);
5425   }
5426   in.tetrahedronvolumelist = NULL;
5427 
5428   {
5429     const PetscInt numCorners  = 4;
5430     const PetscInt numCells    = out.numberoftetrahedra;
5431     const PetscInt numVertices = out.numberofpoints;
5432     const int     *cells      = out.tetrahedronlist;
5433     const double  *meshCoords = out.pointlist;
5434     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5435 
5436     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5437     /* Set labels */
5438     for (v = 0; v < numVertices; ++v) {
5439       if (out.pointmarkerlist[v]) {
5440         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5441       }
5442     }
5443     if (interpolate) {
5444       PetscInt e, f;
5445 
5446       for (e = 0; e < out.numberofedges; e++) {
5447         if (out.edgemarkerlist[e]) {
5448           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5449           const PetscInt *edges;
5450           PetscInt        numEdges;
5451 
5452           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5453           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5454           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5455           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5456         }
5457       }
5458       for (f = 0; f < out.numberoftrifaces; f++) {
5459         if (out.trifacemarkerlist[f]) {
5460           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5461           const PetscInt *faces;
5462           PetscInt        numFaces;
5463 
5464           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5465           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5466           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5467           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5468         }
5469       }
5470     }
5471     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5472   }
5473   PetscFunctionReturn(0);
5474 }
5475 #endif
5476 
5477 #if defined(PETSC_HAVE_CTETGEN)
5478 #include "ctetgen.h"
5479 
5480 #undef __FUNCT__
5481 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5482 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5483 {
5484   MPI_Comm       comm;
5485   const PetscInt dim  = 3;
5486   PLC           *in, *out;
5487   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5488   PetscMPIInt    rank;
5489   PetscErrorCode ierr;
5490 
5491   PetscFunctionBegin;
5492   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5493   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5494   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5495   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5496   ierr = PLCCreate(&in);CHKERRQ(ierr);
5497   ierr = PLCCreate(&out);CHKERRQ(ierr);
5498 
5499   in->numberofpoints = vEnd - vStart;
5500   if (in->numberofpoints > 0) {
5501     PetscSection coordSection;
5502     Vec          coordinates;
5503     PetscScalar *array;
5504 
5505     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5506     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5507     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5508     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5509     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5510     for (v = vStart; v < vEnd; ++v) {
5511       const PetscInt idx = v - vStart;
5512       PetscInt       off, d, m;
5513 
5514       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5515       for (d = 0; d < dim; ++d) {
5516         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5517       }
5518       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5519 
5520       in->pointmarkerlist[idx] = (int) m;
5521     }
5522     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5523   }
5524   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5525 
5526   in->numberoffacets = fEnd - fStart;
5527   if (in->numberoffacets > 0) {
5528     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5529     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5530     for (f = fStart; f < fEnd; ++f) {
5531       const PetscInt idx     = f - fStart;
5532       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5533       polygon       *poly;
5534 
5535       in->facetlist[idx].numberofpolygons = 1;
5536 
5537       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5538 
5539       in->facetlist[idx].numberofholes    = 0;
5540       in->facetlist[idx].holelist         = NULL;
5541 
5542       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5543       for (p = 0; p < numPoints*2; p += 2) {
5544         const PetscInt point = points[p];
5545         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5546       }
5547 
5548       poly                   = in->facetlist[idx].polygonlist;
5549       poly->numberofvertices = numVertices;
5550       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5551       for (v = 0; v < numVertices; ++v) {
5552         const PetscInt vIdx = points[v] - vStart;
5553         poly->vertexlist[v] = vIdx;
5554       }
5555       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5556       in->facetmarkerlist[idx] = (int) m;
5557       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5558     }
5559   }
5560   if (!rank) {
5561     TetGenOpts t;
5562 
5563     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5564     t.in        = boundary; /* Should go away */
5565     t.plc       = 1;
5566     t.quality   = 1;
5567     t.edgesout  = 1;
5568     t.zeroindex = 1;
5569     t.quiet     = 1;
5570     t.verbose   = verbose;
5571     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5572     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5573   }
5574   {
5575     const PetscInt numCorners  = 4;
5576     const PetscInt numCells    = out->numberoftetrahedra;
5577     const PetscInt numVertices = out->numberofpoints;
5578     const int     *cells      = out->tetrahedronlist;
5579     const double  *meshCoords = out->pointlist;
5580 
5581     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5582     /* Set labels */
5583     for (v = 0; v < numVertices; ++v) {
5584       if (out->pointmarkerlist[v]) {
5585         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5586       }
5587     }
5588     if (interpolate) {
5589       PetscInt e;
5590 
5591       for (e = 0; e < out->numberofedges; e++) {
5592         if (out->edgemarkerlist[e]) {
5593           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5594           const PetscInt *edges;
5595           PetscInt        numEdges;
5596 
5597           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5598           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5599           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5600           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5601         }
5602       }
5603       for (f = 0; f < out->numberoftrifaces; f++) {
5604         if (out->trifacemarkerlist[f]) {
5605           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5606           const PetscInt *faces;
5607           PetscInt        numFaces;
5608 
5609           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5610           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5611           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5612           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5613         }
5614       }
5615     }
5616     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5617   }
5618 
5619   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5620   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5621   PetscFunctionReturn(0);
5622 }
5623 
5624 #undef __FUNCT__
5625 #define __FUNCT__ "DMPlexRefine_CTetgen"
5626 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5627 {
5628   MPI_Comm       comm;
5629   const PetscInt dim  = 3;
5630   PLC           *in, *out;
5631   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5632   PetscMPIInt    rank;
5633   PetscErrorCode ierr;
5634 
5635   PetscFunctionBegin;
5636   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5637   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5638   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5639   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5640   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5641   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5642   ierr = PLCCreate(&in);CHKERRQ(ierr);
5643   ierr = PLCCreate(&out);CHKERRQ(ierr);
5644 
5645   in->numberofpoints = vEnd - vStart;
5646   if (in->numberofpoints > 0) {
5647     PetscSection coordSection;
5648     Vec          coordinates;
5649     PetscScalar *array;
5650 
5651     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5652     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5653     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5654     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5655     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5656     for (v = vStart; v < vEnd; ++v) {
5657       const PetscInt idx = v - vStart;
5658       PetscInt       off, d, m;
5659 
5660       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5661       for (d = 0; d < dim; ++d) {
5662         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5663       }
5664       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5665 
5666       in->pointmarkerlist[idx] = (int) m;
5667     }
5668     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5669   }
5670   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5671 
5672   in->numberofcorners       = 4;
5673   in->numberoftetrahedra    = cEnd - cStart;
5674   in->tetrahedronvolumelist = maxVolumes;
5675   if (in->numberoftetrahedra > 0) {
5676     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5677     for (c = cStart; c < cEnd; ++c) {
5678       const PetscInt idx      = c - cStart;
5679       PetscInt      *closure = NULL;
5680       PetscInt       closureSize;
5681 
5682       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5683       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5684       for (v = 0; v < 4; ++v) {
5685         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5686       }
5687       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5688     }
5689   }
5690   if (!rank) {
5691     TetGenOpts t;
5692 
5693     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5694 
5695     t.in        = dm; /* Should go away */
5696     t.refine    = 1;
5697     t.varvolume = 1;
5698     t.quality   = 1;
5699     t.edgesout  = 1;
5700     t.zeroindex = 1;
5701     t.quiet     = 1;
5702     t.verbose   = verbose; /* Change this */
5703 
5704     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5705     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5706   }
5707   {
5708     const PetscInt numCorners  = 4;
5709     const PetscInt numCells    = out->numberoftetrahedra;
5710     const PetscInt numVertices = out->numberofpoints;
5711     const int     *cells       = out->tetrahedronlist;
5712     const double  *meshCoords  = out->pointlist;
5713     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5714 
5715     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5716     /* Set labels */
5717     for (v = 0; v < numVertices; ++v) {
5718       if (out->pointmarkerlist[v]) {
5719         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5720       }
5721     }
5722     if (interpolate) {
5723       PetscInt e, f;
5724 
5725       for (e = 0; e < out->numberofedges; e++) {
5726         if (out->edgemarkerlist[e]) {
5727           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5728           const PetscInt *edges;
5729           PetscInt        numEdges;
5730 
5731           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5732           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5733           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5734           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5735         }
5736       }
5737       for (f = 0; f < out->numberoftrifaces; f++) {
5738         if (out->trifacemarkerlist[f]) {
5739           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5740           const PetscInt *faces;
5741           PetscInt        numFaces;
5742 
5743           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5744           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5745           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5746           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5747         }
5748       }
5749     }
5750     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5751   }
5752   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5753   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5754   PetscFunctionReturn(0);
5755 }
5756 #endif
5757 
5758 #undef __FUNCT__
5759 #define __FUNCT__ "DMPlexGenerate"
5760 /*@C
5761   DMPlexGenerate - Generates a mesh.
5762 
5763   Not Collective
5764 
5765   Input Parameters:
5766 + boundary - The DMPlex boundary object
5767 . name - The mesh generation package name
5768 - interpolate - Flag to create intermediate mesh elements
5769 
5770   Output Parameter:
5771 . mesh - The DMPlex object
5772 
5773   Level: intermediate
5774 
5775 .keywords: mesh, elements
5776 .seealso: DMPlexCreate(), DMRefine()
5777 @*/
5778 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5779 {
5780   PetscInt       dim;
5781   char           genname[1024];
5782   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5783   PetscErrorCode ierr;
5784 
5785   PetscFunctionBegin;
5786   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5787   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5788   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5789   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5790   if (flg) name = genname;
5791   if (name) {
5792     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5793     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5794     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5795   }
5796   switch (dim) {
5797   case 1:
5798     if (!name || isTriangle) {
5799 #if defined(PETSC_HAVE_TRIANGLE)
5800       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5801 #else
5802       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5803 #endif
5804     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5805     break;
5806   case 2:
5807     if (!name || isCTetgen) {
5808 #if defined(PETSC_HAVE_CTETGEN)
5809       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5810 #else
5811       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5812 #endif
5813     } else if (isTetgen) {
5814 #if defined(PETSC_HAVE_TETGEN)
5815       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5816 #else
5817       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5818 #endif
5819     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5820     break;
5821   default:
5822     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5823   }
5824   PetscFunctionReturn(0);
5825 }
5826 
5827 typedef PetscInt CellRefiner;
5828 
5829 #undef __FUNCT__
5830 #define __FUNCT__ "GetDepthStart_Private"
5831 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5832 {
5833   PetscFunctionBegin;
5834   if (cStart) *cStart = 0;
5835   if (vStart) *vStart = depthSize[depth];
5836   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5837   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5838   PetscFunctionReturn(0);
5839 }
5840 
5841 #undef __FUNCT__
5842 #define __FUNCT__ "GetDepthEnd_Private"
5843 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5844 {
5845   PetscFunctionBegin;
5846   if (cEnd) *cEnd = depthSize[depth];
5847   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5848   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5849   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5850   PetscFunctionReturn(0);
5851 }
5852 
5853 #undef __FUNCT__
5854 #define __FUNCT__ "CellRefinerGetSizes"
5855 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5856 {
5857   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5858   PetscErrorCode ierr;
5859 
5860   PetscFunctionBegin;
5861   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5862   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5863   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5864   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5865   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5866   switch (refiner) {
5867   case 1:
5868     /* Simplicial 2D */
5869     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5870     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5871     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5872     break;
5873   case 3:
5874     /* Hybrid 2D */
5875     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5876     cMax = PetscMin(cEnd, cMax);
5877     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5878     fMax         = PetscMin(fEnd, fMax);
5879     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5880     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 */
5881     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5882     break;
5883   case 2:
5884     /* Hex 2D */
5885     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5886     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5887     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5888     break;
5889   default:
5890     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5891   }
5892   PetscFunctionReturn(0);
5893 }
5894 
5895 #undef __FUNCT__
5896 #define __FUNCT__ "CellRefinerSetConeSizes"
5897 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5898 {
5899   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5900   PetscErrorCode ierr;
5901 
5902   PetscFunctionBegin;
5903   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5904   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5905   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5906   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5907   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5908   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5909   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5910   switch (refiner) {
5911   case 1:
5912     /* Simplicial 2D */
5913     /* All cells have 3 faces */
5914     for (c = cStart; c < cEnd; ++c) {
5915       for (r = 0; r < 4; ++r) {
5916         const PetscInt newp = (c - cStart)*4 + r;
5917 
5918         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5919       }
5920     }
5921     /* Split faces have 2 vertices and the same cells as the parent */
5922     for (f = fStart; f < fEnd; ++f) {
5923       for (r = 0; r < 2; ++r) {
5924         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5925         PetscInt       size;
5926 
5927         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5928         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5929         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5930       }
5931     }
5932     /* Interior faces have 2 vertices and 2 cells */
5933     for (c = cStart; c < cEnd; ++c) {
5934       for (r = 0; r < 3; ++r) {
5935         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5936 
5937         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5938         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5939       }
5940     }
5941     /* Old vertices have identical supports */
5942     for (v = vStart; v < vEnd; ++v) {
5943       const PetscInt newp = vStartNew + (v - vStart);
5944       PetscInt       size;
5945 
5946       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5947       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5948     }
5949     /* Face vertices have 2 + cells*2 supports */
5950     for (f = fStart; f < fEnd; ++f) {
5951       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5952       PetscInt       size;
5953 
5954       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5955       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5956     }
5957     break;
5958   case 2:
5959     /* Hex 2D */
5960     /* All cells have 4 faces */
5961     for (c = cStart; c < cEnd; ++c) {
5962       for (r = 0; r < 4; ++r) {
5963         const PetscInt newp = (c - cStart)*4 + r;
5964 
5965         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5966       }
5967     }
5968     /* Split faces have 2 vertices and the same cells as the parent */
5969     for (f = fStart; f < fEnd; ++f) {
5970       for (r = 0; r < 2; ++r) {
5971         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5972         PetscInt       size;
5973 
5974         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5975         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5976         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5977       }
5978     }
5979     /* Interior faces have 2 vertices and 2 cells */
5980     for (c = cStart; c < cEnd; ++c) {
5981       for (r = 0; r < 4; ++r) {
5982         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5983 
5984         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5985         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5986       }
5987     }
5988     /* Old vertices have identical supports */
5989     for (v = vStart; v < vEnd; ++v) {
5990       const PetscInt newp = vStartNew + (v - vStart);
5991       PetscInt       size;
5992 
5993       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5994       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5995     }
5996     /* Face vertices have 2 + cells supports */
5997     for (f = fStart; f < fEnd; ++f) {
5998       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5999       PetscInt       size;
6000 
6001       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6002       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
6003     }
6004     /* Cell vertices have 4 supports */
6005     for (c = cStart; c < cEnd; ++c) {
6006       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6007 
6008       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
6009     }
6010     break;
6011   case 3:
6012     /* Hybrid 2D */
6013     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6014     cMax = PetscMin(cEnd, cMax);
6015     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6016     fMax = PetscMin(fEnd, fMax);
6017     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6018     /* Interior cells have 3 faces */
6019     for (c = cStart; c < cMax; ++c) {
6020       for (r = 0; r < 4; ++r) {
6021         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6022 
6023         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6024       }
6025     }
6026     /* Hybrid cells have 4 faces */
6027     for (c = cMax; c < cEnd; ++c) {
6028       for (r = 0; r < 2; ++r) {
6029         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6030 
6031         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6032       }
6033     }
6034     /* Interior split faces have 2 vertices and the same cells as the parent */
6035     for (f = fStart; f < fMax; ++f) {
6036       for (r = 0; r < 2; ++r) {
6037         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6038         PetscInt       size;
6039 
6040         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6041         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6042         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6043       }
6044     }
6045     /* Interior cell faces have 2 vertices and 2 cells */
6046     for (c = cStart; c < cMax; ++c) {
6047       for (r = 0; r < 3; ++r) {
6048         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6049 
6050         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6051         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6052       }
6053     }
6054     /* Hybrid faces have 2 vertices and the same cells */
6055     for (f = fMax; f < fEnd; ++f) {
6056       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6057       PetscInt       size;
6058 
6059       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6060       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6061       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6062     }
6063     /* Hybrid cell faces have 2 vertices and 2 cells */
6064     for (c = cMax; c < cEnd; ++c) {
6065       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6066 
6067       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6068       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6069     }
6070     /* Old vertices have identical supports */
6071     for (v = vStart; v < vEnd; ++v) {
6072       const PetscInt newp = vStartNew + (v - vStart);
6073       PetscInt       size;
6074 
6075       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6076       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6077     }
6078     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6079     for (f = fStart; f < fMax; ++f) {
6080       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6081       const PetscInt *support;
6082       PetscInt       size, newSize = 2, s;
6083 
6084       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6085       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6086       for (s = 0; s < size; ++s) {
6087         if (support[s] >= cMax) newSize += 1;
6088         else newSize += 2;
6089       }
6090       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6091     }
6092     break;
6093   default:
6094     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6095   }
6096   PetscFunctionReturn(0);
6097 }
6098 
6099 #undef __FUNCT__
6100 #define __FUNCT__ "CellRefinerSetCones"
6101 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6102 {
6103   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;
6104   PetscInt       maxSupportSize, *supportRef;
6105   PetscErrorCode ierr;
6106 
6107   PetscFunctionBegin;
6108   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6109   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6110   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6111   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6112   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6113   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6114   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6115   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6116   switch (refiner) {
6117   case 1:
6118     /* Simplicial 2D */
6119     /*
6120      2
6121      |\
6122      | \
6123      |  \
6124      |   \
6125      | C  \
6126      |     \
6127      |      \
6128      2---1---1
6129      |\  D  / \
6130      | 2   0   \
6131      |A \ /  B  \
6132      0---0-------1
6133      */
6134     /* All cells have 3 faces */
6135     for (c = cStart; c < cEnd; ++c) {
6136       const PetscInt  newp = cStartNew + (c - cStart)*4;
6137       const PetscInt *cone, *ornt;
6138       PetscInt        coneNew[3], orntNew[3];
6139 
6140       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6141       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6142       /* A triangle */
6143       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6144       orntNew[0] = ornt[0];
6145       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6146       orntNew[1] = -2;
6147       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6148       orntNew[2] = ornt[2];
6149       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6150       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6151 #if 1
6152       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);
6153       for (p = 0; p < 3; ++p) {
6154         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);
6155       }
6156 #endif
6157       /* B triangle */
6158       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6159       orntNew[0] = ornt[0];
6160       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6161       orntNew[1] = ornt[1];
6162       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6163       orntNew[2] = -2;
6164       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6165       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6166 #if 1
6167       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);
6168       for (p = 0; p < 3; ++p) {
6169         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);
6170       }
6171 #endif
6172       /* C triangle */
6173       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6174       orntNew[0] = -2;
6175       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6176       orntNew[1] = ornt[1];
6177       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6178       orntNew[2] = ornt[2];
6179       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6180       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6181 #if 1
6182       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);
6183       for (p = 0; p < 3; ++p) {
6184         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);
6185       }
6186 #endif
6187       /* D triangle */
6188       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6189       orntNew[0] = 0;
6190       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6191       orntNew[1] = 0;
6192       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6193       orntNew[2] = 0;
6194       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6195       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6196 #if 1
6197       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);
6198       for (p = 0; p < 3; ++p) {
6199         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);
6200       }
6201 #endif
6202     }
6203     /* Split faces have 2 vertices and the same cells as the parent */
6204     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6205     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6206     for (f = fStart; f < fEnd; ++f) {
6207       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6208 
6209       for (r = 0; r < 2; ++r) {
6210         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6211         const PetscInt *cone, *support;
6212         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6213 
6214         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6215         coneNew[0]       = vStartNew + (cone[0] - vStart);
6216         coneNew[1]       = vStartNew + (cone[1] - vStart);
6217         coneNew[(r+1)%2] = newv;
6218         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6219 #if 1
6220         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6221         for (p = 0; p < 2; ++p) {
6222           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);
6223         }
6224 #endif
6225         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6226         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6227         for (s = 0; s < supportSize; ++s) {
6228           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6229           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6230           for (c = 0; c < coneSize; ++c) {
6231             if (cone[c] == f) break;
6232           }
6233           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6234         }
6235         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6236 #if 1
6237         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6238         for (p = 0; p < supportSize; ++p) {
6239           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);
6240         }
6241 #endif
6242       }
6243     }
6244     /* Interior faces have 2 vertices and 2 cells */
6245     for (c = cStart; c < cEnd; ++c) {
6246       const PetscInt *cone;
6247 
6248       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6249       for (r = 0; r < 3; ++r) {
6250         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6251         PetscInt       coneNew[2];
6252         PetscInt       supportNew[2];
6253 
6254         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6255         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6256         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6257 #if 1
6258         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6259         for (p = 0; p < 2; ++p) {
6260           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);
6261         }
6262 #endif
6263         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6264         supportNew[1] = (c - cStart)*4 + 3;
6265         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6266 #if 1
6267         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6268         for (p = 0; p < 2; ++p) {
6269           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);
6270         }
6271 #endif
6272       }
6273     }
6274     /* Old vertices have identical supports */
6275     for (v = vStart; v < vEnd; ++v) {
6276       const PetscInt  newp = vStartNew + (v - vStart);
6277       const PetscInt *support, *cone;
6278       PetscInt        size, s;
6279 
6280       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6281       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6282       for (s = 0; s < size; ++s) {
6283         PetscInt r = 0;
6284 
6285         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6286         if (cone[1] == v) r = 1;
6287         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6288       }
6289       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6290 #if 1
6291       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6292       for (p = 0; p < size; ++p) {
6293         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);
6294       }
6295 #endif
6296     }
6297     /* Face vertices have 2 + cells*2 supports */
6298     for (f = fStart; f < fEnd; ++f) {
6299       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6300       const PetscInt *cone, *support;
6301       PetscInt        size, s;
6302 
6303       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6304       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6305       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6306       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6307       for (s = 0; s < size; ++s) {
6308         PetscInt r = 0;
6309 
6310         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6311         if      (cone[1] == f) r = 1;
6312         else if (cone[2] == f) r = 2;
6313         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6314         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6315       }
6316       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6317 #if 1
6318       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6319       for (p = 0; p < 2+size*2; ++p) {
6320         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);
6321       }
6322 #endif
6323     }
6324     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6325     break;
6326   case 2:
6327     /* Hex 2D */
6328     /*
6329      3---------2---------2
6330      |         |         |
6331      |    D    2    C    |
6332      |         |         |
6333      3----3----0----1----1
6334      |         |         |
6335      |    A    0    B    |
6336      |         |         |
6337      0---------0---------1
6338      */
6339     /* All cells have 4 faces */
6340     for (c = cStart; c < cEnd; ++c) {
6341       const PetscInt  newp = (c - cStart)*4;
6342       const PetscInt *cone, *ornt;
6343       PetscInt        coneNew[4], orntNew[4];
6344 
6345       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6346       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6347       /* A quad */
6348       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6349       orntNew[0] = ornt[0];
6350       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6351       orntNew[1] = 0;
6352       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6353       orntNew[2] = -2;
6354       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6355       orntNew[3] = ornt[3];
6356       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6357       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6358 #if 1
6359       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);
6360       for (p = 0; p < 4; ++p) {
6361         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);
6362       }
6363 #endif
6364       /* B quad */
6365       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6366       orntNew[0] = ornt[0];
6367       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6368       orntNew[1] = ornt[1];
6369       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6370       orntNew[2] = 0;
6371       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6372       orntNew[3] = -2;
6373       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6374       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6375 #if 1
6376       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);
6377       for (p = 0; p < 4; ++p) {
6378         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);
6379       }
6380 #endif
6381       /* C quad */
6382       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6383       orntNew[0] = -2;
6384       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6385       orntNew[1] = ornt[1];
6386       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6387       orntNew[2] = ornt[2];
6388       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6389       orntNew[3] = 0;
6390       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6391       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6392 #if 1
6393       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);
6394       for (p = 0; p < 4; ++p) {
6395         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);
6396       }
6397 #endif
6398       /* D quad */
6399       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6400       orntNew[0] = 0;
6401       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6402       orntNew[1] = -2;
6403       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6404       orntNew[2] = ornt[2];
6405       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6406       orntNew[3] = ornt[3];
6407       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6408       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6409 #if 1
6410       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);
6411       for (p = 0; p < 4; ++p) {
6412         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);
6413       }
6414 #endif
6415     }
6416     /* Split faces have 2 vertices and the same cells as the parent */
6417     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6418     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6419     for (f = fStart; f < fEnd; ++f) {
6420       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6421 
6422       for (r = 0; r < 2; ++r) {
6423         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6424         const PetscInt *cone, *support;
6425         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6426 
6427         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6428         coneNew[0]       = vStartNew + (cone[0] - vStart);
6429         coneNew[1]       = vStartNew + (cone[1] - vStart);
6430         coneNew[(r+1)%2] = newv;
6431         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6432 #if 1
6433         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6434         for (p = 0; p < 2; ++p) {
6435           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);
6436         }
6437 #endif
6438         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6439         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6440         for (s = 0; s < supportSize; ++s) {
6441           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6442           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6443           for (c = 0; c < coneSize; ++c) {
6444             if (cone[c] == f) break;
6445           }
6446           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6447         }
6448         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6449 #if 1
6450         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6451         for (p = 0; p < supportSize; ++p) {
6452           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);
6453         }
6454 #endif
6455       }
6456     }
6457     /* Interior faces have 2 vertices and 2 cells */
6458     for (c = cStart; c < cEnd; ++c) {
6459       const PetscInt *cone;
6460       PetscInt        coneNew[2], supportNew[2];
6461 
6462       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6463       for (r = 0; r < 4; ++r) {
6464         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6465 
6466         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6467         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6468         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6469 #if 1
6470         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6471         for (p = 0; p < 2; ++p) {
6472           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);
6473         }
6474 #endif
6475         supportNew[0] = (c - cStart)*4 + r;
6476         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6477         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6478 #if 1
6479         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6480         for (p = 0; p < 2; ++p) {
6481           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);
6482         }
6483 #endif
6484       }
6485     }
6486     /* Old vertices have identical supports */
6487     for (v = vStart; v < vEnd; ++v) {
6488       const PetscInt  newp = vStartNew + (v - vStart);
6489       const PetscInt *support, *cone;
6490       PetscInt        size, s;
6491 
6492       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6493       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6494       for (s = 0; s < size; ++s) {
6495         PetscInt r = 0;
6496 
6497         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6498         if (cone[1] == v) r = 1;
6499         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6500       }
6501       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6502 #if 1
6503       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6504       for (p = 0; p < size; ++p) {
6505         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);
6506       }
6507 #endif
6508     }
6509     /* Face vertices have 2 + cells supports */
6510     for (f = fStart; f < fEnd; ++f) {
6511       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6512       const PetscInt *cone, *support;
6513       PetscInt        size, s;
6514 
6515       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6516       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6517       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6518       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6519       for (s = 0; s < size; ++s) {
6520         PetscInt r = 0;
6521 
6522         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6523         if      (cone[1] == f) r = 1;
6524         else if (cone[2] == f) r = 2;
6525         else if (cone[3] == f) r = 3;
6526         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6527       }
6528       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6529 #if 1
6530       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6531       for (p = 0; p < 2+size; ++p) {
6532         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);
6533       }
6534 #endif
6535     }
6536     /* Cell vertices have 4 supports */
6537     for (c = cStart; c < cEnd; ++c) {
6538       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6539       PetscInt       supportNew[4];
6540 
6541       for (r = 0; r < 4; ++r) {
6542         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6543       }
6544       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6545     }
6546     break;
6547   case 3:
6548     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6549     cMax = PetscMin(cEnd, cMax);
6550     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6551     fMax = PetscMin(fEnd, fMax);
6552     /* Interior cells have 3 faces */
6553     for (c = cStart; c < cMax; ++c) {
6554       const PetscInt  newp = cStartNew + (c - cStart)*4;
6555       const PetscInt *cone, *ornt;
6556       PetscInt        coneNew[3], orntNew[3];
6557 
6558       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6559       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6560       /* A triangle */
6561       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6562       orntNew[0] = ornt[0];
6563       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6564       orntNew[1] = -2;
6565       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6566       orntNew[2] = ornt[2];
6567       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6568       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6569 #if 1
6570       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);
6571       for (p = 0; p < 3; ++p) {
6572         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);
6573       }
6574 #endif
6575       /* B triangle */
6576       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6577       orntNew[0] = ornt[0];
6578       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6579       orntNew[1] = ornt[1];
6580       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6581       orntNew[2] = -2;
6582       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6583       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6584 #if 1
6585       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);
6586       for (p = 0; p < 3; ++p) {
6587         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);
6588       }
6589 #endif
6590       /* C triangle */
6591       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6592       orntNew[0] = -2;
6593       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6594       orntNew[1] = ornt[1];
6595       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6596       orntNew[2] = ornt[2];
6597       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6598       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6599 #if 1
6600       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);
6601       for (p = 0; p < 3; ++p) {
6602         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);
6603       }
6604 #endif
6605       /* D triangle */
6606       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6607       orntNew[0] = 0;
6608       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6609       orntNew[1] = 0;
6610       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6611       orntNew[2] = 0;
6612       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6613       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6614 #if 1
6615       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);
6616       for (p = 0; p < 3; ++p) {
6617         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);
6618       }
6619 #endif
6620     }
6621     /*
6622      2----3----3
6623      |         |
6624      |    B    |
6625      |         |
6626      0----4--- 1
6627      |         |
6628      |    A    |
6629      |         |
6630      0----2----1
6631      */
6632     /* Hybrid cells have 4 faces */
6633     for (c = cMax; c < cEnd; ++c) {
6634       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6635       const PetscInt *cone, *ornt;
6636       PetscInt        coneNew[4], orntNew[4];
6637 
6638       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6639       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6640       /* A quad */
6641       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6642       orntNew[0] = ornt[0];
6643       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6644       orntNew[1] = ornt[1];
6645       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6646       orntNew[2] = 0;
6647       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6648       orntNew[3] = 0;
6649       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6650       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6651 #if 1
6652       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);
6653       for (p = 0; p < 4; ++p) {
6654         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);
6655       }
6656 #endif
6657       /* B quad */
6658       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6659       orntNew[0] = ornt[0];
6660       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6661       orntNew[1] = ornt[1];
6662       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6663       orntNew[2] = 0;
6664       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6665       orntNew[3] = 0;
6666       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6667       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6668 #if 1
6669       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);
6670       for (p = 0; p < 4; ++p) {
6671         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);
6672       }
6673 #endif
6674     }
6675     /* Interior split faces have 2 vertices and the same cells as the parent */
6676     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6677     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6678     for (f = fStart; f < fMax; ++f) {
6679       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6680 
6681       for (r = 0; r < 2; ++r) {
6682         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6683         const PetscInt *cone, *support;
6684         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6685 
6686         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6687         coneNew[0]       = vStartNew + (cone[0] - vStart);
6688         coneNew[1]       = vStartNew + (cone[1] - vStart);
6689         coneNew[(r+1)%2] = newv;
6690         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6691 #if 1
6692         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6693         for (p = 0; p < 2; ++p) {
6694           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);
6695         }
6696 #endif
6697         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6698         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6699         for (s = 0; s < supportSize; ++s) {
6700           if (support[s] >= cMax) {
6701             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6702           } else {
6703             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6704             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6705             for (c = 0; c < coneSize; ++c) {
6706               if (cone[c] == f) break;
6707             }
6708             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6709           }
6710         }
6711         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6712 #if 1
6713         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6714         for (p = 0; p < supportSize; ++p) {
6715           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);
6716         }
6717 #endif
6718       }
6719     }
6720     /* Interior cell faces have 2 vertices and 2 cells */
6721     for (c = cStart; c < cMax; ++c) {
6722       const PetscInt *cone;
6723 
6724       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6725       for (r = 0; r < 3; ++r) {
6726         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6727         PetscInt       coneNew[2];
6728         PetscInt       supportNew[2];
6729 
6730         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6731         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6732         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6733 #if 1
6734         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6735         for (p = 0; p < 2; ++p) {
6736           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);
6737         }
6738 #endif
6739         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6740         supportNew[1] = (c - cStart)*4 + 3;
6741         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6742 #if 1
6743         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6744         for (p = 0; p < 2; ++p) {
6745           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);
6746         }
6747 #endif
6748       }
6749     }
6750     /* Interior hybrid faces have 2 vertices and the same cells */
6751     for (f = fMax; f < fEnd; ++f) {
6752       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6753       const PetscInt *cone;
6754       const PetscInt *support;
6755       PetscInt        coneNew[2];
6756       PetscInt        supportNew[2];
6757       PetscInt        size, s, r;
6758 
6759       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6760       coneNew[0] = vStartNew + (cone[0] - vStart);
6761       coneNew[1] = vStartNew + (cone[1] - vStart);
6762       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6763 #if 1
6764       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6765       for (p = 0; p < 2; ++p) {
6766         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);
6767       }
6768 #endif
6769       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6770       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6771       for (s = 0; s < size; ++s) {
6772         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6773         for (r = 0; r < 2; ++r) {
6774           if (cone[r+2] == f) break;
6775         }
6776         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6777       }
6778       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6779 #if 1
6780       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6781       for (p = 0; p < size; ++p) {
6782         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);
6783       }
6784 #endif
6785     }
6786     /* Cell hybrid faces have 2 vertices and 2 cells */
6787     for (c = cMax; c < cEnd; ++c) {
6788       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6789       const PetscInt *cone;
6790       PetscInt        coneNew[2];
6791       PetscInt        supportNew[2];
6792 
6793       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6794       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6795       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6796       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6797 #if 1
6798       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6799       for (p = 0; p < 2; ++p) {
6800         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);
6801       }
6802 #endif
6803       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6804       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6805       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6806 #if 1
6807       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6808       for (p = 0; p < 2; ++p) {
6809         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);
6810       }
6811 #endif
6812     }
6813     /* Old vertices have identical supports */
6814     for (v = vStart; v < vEnd; ++v) {
6815       const PetscInt  newp = vStartNew + (v - vStart);
6816       const PetscInt *support, *cone;
6817       PetscInt        size, s;
6818 
6819       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6820       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6821       for (s = 0; s < size; ++s) {
6822         if (support[s] >= fMax) {
6823           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6824         } else {
6825           PetscInt r = 0;
6826 
6827           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6828           if (cone[1] == v) r = 1;
6829           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6830         }
6831       }
6832       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6833 #if 1
6834       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6835       for (p = 0; p < size; ++p) {
6836         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);
6837       }
6838 #endif
6839     }
6840     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6841     for (f = fStart; f < fMax; ++f) {
6842       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6843       const PetscInt *cone, *support;
6844       PetscInt        size, newSize = 2, s;
6845 
6846       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6847       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6848       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6849       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6850       for (s = 0; s < size; ++s) {
6851         PetscInt r = 0;
6852 
6853         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6854         if (support[s] >= cMax) {
6855           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6856 
6857           newSize += 1;
6858         } else {
6859           if      (cone[1] == f) r = 1;
6860           else if (cone[2] == f) r = 2;
6861           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6862           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6863 
6864           newSize += 2;
6865         }
6866       }
6867       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6868 #if 1
6869       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6870       for (p = 0; p < newSize; ++p) {
6871         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);
6872       }
6873 #endif
6874     }
6875     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6876     break;
6877   default:
6878     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6879   }
6880   PetscFunctionReturn(0);
6881 }
6882 
6883 #undef __FUNCT__
6884 #define __FUNCT__ "CellRefinerSetCoordinates"
6885 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6886 {
6887   PetscSection   coordSection, coordSectionNew;
6888   Vec            coordinates, coordinatesNew;
6889   PetscScalar   *coords, *coordsNew;
6890   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6891   PetscErrorCode ierr;
6892 
6893   PetscFunctionBegin;
6894   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6895   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6896   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6897   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6898   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6899   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6900   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6901   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6902   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6903   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6904   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6905   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6906   if (fMax < 0) fMax = fEnd;
6907   switch (refiner) {
6908   case 1:
6909   case 2:
6910   case 3:
6911     /* Simplicial and Hex 2D */
6912     /* All vertices have the dim coordinates */
6913     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6914       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6915       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6916     }
6917     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6918     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6919     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6920     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6921     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6922     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6923     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6924     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6925     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6926     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6927     /* Old vertices have the same coordinates */
6928     for (v = vStart; v < vEnd; ++v) {
6929       const PetscInt newv = vStartNew + (v - vStart);
6930       PetscInt       off, offnew, d;
6931 
6932       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6934       for (d = 0; d < dim; ++d) {
6935         coordsNew[offnew+d] = coords[off+d];
6936       }
6937     }
6938     /* Face vertices have the average of endpoint coordinates */
6939     for (f = fStart; f < fMax; ++f) {
6940       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6941       const PetscInt *cone;
6942       PetscInt        coneSize, offA, offB, offnew, d;
6943 
6944       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6945       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6946       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6947       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6948       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6949       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6950       for (d = 0; d < dim; ++d) {
6951         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6952       }
6953     }
6954     /* Just Hex 2D */
6955     if (refiner == 2) {
6956       /* Cell vertices have the average of corner coordinates */
6957       for (c = cStart; c < cEnd; ++c) {
6958         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6959         PetscInt      *cone = NULL;
6960         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6961 
6962         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6963         for (p = 0; p < closureSize*2; p += 2) {
6964           const PetscInt point = cone[p];
6965           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6966         }
6967         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6968         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6969         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6970         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6971         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6972         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6973         for (d = 0; d < dim; ++d) {
6974           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6975         }
6976         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6977       }
6978     }
6979     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6980     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6981     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6982     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6983     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6984     break;
6985   default:
6986     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6987   }
6988   PetscFunctionReturn(0);
6989 }
6990 
6991 #undef __FUNCT__
6992 #define __FUNCT__ "DMPlexCreateProcessSF"
6993 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6994 {
6995   PetscInt           numRoots, numLeaves, l;
6996   const PetscInt    *localPoints;
6997   const PetscSFNode *remotePoints;
6998   PetscInt          *localPointsNew;
6999   PetscSFNode       *remotePointsNew;
7000   PetscInt          *ranks, *ranksNew;
7001   PetscErrorCode     ierr;
7002 
7003   PetscFunctionBegin;
7004   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7005   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
7006   for (l = 0; l < numLeaves; ++l) {
7007     ranks[l] = remotePoints[l].rank;
7008   }
7009   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7010   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
7011   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7012   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7013   for (l = 0; l < numLeaves; ++l) {
7014     ranksNew[l]              = ranks[l];
7015     localPointsNew[l]        = l;
7016     remotePointsNew[l].index = 0;
7017     remotePointsNew[l].rank  = ranksNew[l];
7018   }
7019   ierr = PetscFree(ranks);CHKERRQ(ierr);
7020   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7021   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7022   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7023   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7024   PetscFunctionReturn(0);
7025 }
7026 
7027 #undef __FUNCT__
7028 #define __FUNCT__ "CellRefinerCreateSF"
7029 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7030 {
7031   PetscSF            sf, sfNew, sfProcess;
7032   IS                 processRanks;
7033   MPI_Datatype       depthType;
7034   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7035   const PetscInt    *localPoints, *neighbors;
7036   const PetscSFNode *remotePoints;
7037   PetscInt          *localPointsNew;
7038   PetscSFNode       *remotePointsNew;
7039   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7040   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7041   PetscErrorCode     ierr;
7042 
7043   PetscFunctionBegin;
7044   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7045   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7046   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7047   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7048   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7049   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7050   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7051   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7052   switch (refiner) {
7053   case 3:
7054     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7055     cMax = PetscMin(cEnd, cMax);
7056     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7057     fMax = PetscMin(fEnd, fMax);
7058   }
7059   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7060   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7061   /* Caculate size of new SF */
7062   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7063   if (numRoots < 0) PetscFunctionReturn(0);
7064   for (l = 0; l < numLeaves; ++l) {
7065     const PetscInt p = localPoints[l];
7066 
7067     switch (refiner) {
7068     case 1:
7069       /* Simplicial 2D */
7070       if ((p >= vStart) && (p < vEnd)) {
7071         /* Old vertices stay the same */
7072         ++numLeavesNew;
7073       } else if ((p >= fStart) && (p < fEnd)) {
7074         /* Old faces add new faces and vertex */
7075         numLeavesNew += 1 + 2;
7076       } else if ((p >= cStart) && (p < cEnd)) {
7077         /* Old cells add new cells and interior faces */
7078         numLeavesNew += 4 + 3;
7079       }
7080       break;
7081     case 2:
7082       /* Hex 2D */
7083       if ((p >= vStart) && (p < vEnd)) {
7084         /* Old vertices stay the same */
7085         ++numLeavesNew;
7086       } else if ((p >= fStart) && (p < fEnd)) {
7087         /* Old faces add new faces and vertex */
7088         numLeavesNew += 1 + 2;
7089       } else if ((p >= cStart) && (p < cEnd)) {
7090         /* Old cells add new cells and interior faces */
7091         numLeavesNew += 4 + 4;
7092       }
7093       break;
7094     default:
7095       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7096     }
7097   }
7098   /* Communicate depthSizes for each remote rank */
7099   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7100   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7101   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7102   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);
7103   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7104   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7105   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7106   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7107   for (n = 0; n < numNeighbors; ++n) {
7108     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7109   }
7110   depthSizeOld[depth]   = cMax;
7111   depthSizeOld[0]       = vMax;
7112   depthSizeOld[depth-1] = fMax;
7113   depthSizeOld[1]       = eMax;
7114 
7115   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7116   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7117 
7118   depthSizeOld[depth]   = cEnd - cStart;
7119   depthSizeOld[0]       = vEnd - vStart;
7120   depthSizeOld[depth-1] = fEnd - fStart;
7121   depthSizeOld[1]       = eEnd - eStart;
7122 
7123   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7124   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7125   for (n = 0; n < numNeighbors; ++n) {
7126     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7127   }
7128   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7129   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7130   /* Calculate new point SF */
7131   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7132   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7133   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7134   for (l = 0, m = 0; l < numLeaves; ++l) {
7135     PetscInt    p     = localPoints[l];
7136     PetscInt    rp    = remotePoints[l].index, n;
7137     PetscMPIInt rrank = remotePoints[l].rank;
7138 
7139     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7140     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7141     switch (refiner) {
7142     case 1:
7143       /* Simplicial 2D */
7144       if ((p >= vStart) && (p < vEnd)) {
7145         /* Old vertices stay the same */
7146         localPointsNew[m]        = vStartNew     + (p  - vStart);
7147         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7148         remotePointsNew[m].rank  = rrank;
7149         ++m;
7150       } else if ((p >= fStart) && (p < fEnd)) {
7151         /* Old faces add new faces and vertex */
7152         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7153         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7154         remotePointsNew[m].rank  = rrank;
7155         ++m;
7156         for (r = 0; r < 2; ++r, ++m) {
7157           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7158           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7159           remotePointsNew[m].rank  = rrank;
7160         }
7161       } else if ((p >= cStart) && (p < cEnd)) {
7162         /* Old cells add new cells and interior faces */
7163         for (r = 0; r < 4; ++r, ++m) {
7164           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7165           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7166           remotePointsNew[m].rank  = rrank;
7167         }
7168         for (r = 0; r < 3; ++r, ++m) {
7169           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7170           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7171           remotePointsNew[m].rank  = rrank;
7172         }
7173       }
7174       break;
7175     case 2:
7176       /* Hex 2D */
7177       if ((p >= vStart) && (p < vEnd)) {
7178         /* Old vertices stay the same */
7179         localPointsNew[m]        = vStartNew     + (p  - vStart);
7180         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7181         remotePointsNew[m].rank  = rrank;
7182         ++m;
7183       } else if ((p >= fStart) && (p < fEnd)) {
7184         /* Old faces add new faces and vertex */
7185         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7186         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7187         remotePointsNew[m].rank  = rrank;
7188         ++m;
7189         for (r = 0; r < 2; ++r, ++m) {
7190           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7191           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7192           remotePointsNew[m].rank  = rrank;
7193         }
7194       } else if ((p >= cStart) && (p < cEnd)) {
7195         /* Old cells add new cells and interior faces */
7196         for (r = 0; r < 4; ++r, ++m) {
7197           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7198           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7199           remotePointsNew[m].rank  = rrank;
7200         }
7201         for (r = 0; r < 4; ++r, ++m) {
7202           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7203           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7204           remotePointsNew[m].rank  = rrank;
7205         }
7206       }
7207       break;
7208     case 3:
7209       /* Hybrid simplicial 2D */
7210       if ((p >= vStart) && (p < vEnd)) {
7211         /* Old vertices stay the same */
7212         localPointsNew[m]        = vStartNew     + (p  - vStart);
7213         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7214         remotePointsNew[m].rank  = rrank;
7215         ++m;
7216       } else if ((p >= fStart) && (p < fMax)) {
7217         /* Old interior faces add new faces and vertex */
7218         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7219         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7220         remotePointsNew[m].rank  = rrank;
7221         ++m;
7222         for (r = 0; r < 2; ++r, ++m) {
7223           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7224           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7225           remotePointsNew[m].rank  = rrank;
7226         }
7227       } else if ((p >= fMax) && (p < fEnd)) {
7228         /* Old hybrid faces stay the same */
7229         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7230         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7231         remotePointsNew[m].rank  = rrank;
7232         ++m;
7233       } else if ((p >= cStart) && (p < cMax)) {
7234         /* Old interior cells add new cells and interior faces */
7235         for (r = 0; r < 4; ++r, ++m) {
7236           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7237           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7238           remotePointsNew[m].rank  = rrank;
7239         }
7240         for (r = 0; r < 3; ++r, ++m) {
7241           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7242           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7243           remotePointsNew[m].rank  = rrank;
7244         }
7245       } else if ((p >= cStart) && (p < cMax)) {
7246         /* Old hybrid cells add new cells and hybrid face */
7247         for (r = 0; r < 2; ++r, ++m) {
7248           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7249           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7250           remotePointsNew[m].rank  = rrank;
7251         }
7252         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7253         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]);
7254         remotePointsNew[m].rank  = rrank;
7255         ++m;
7256       }
7257       break;
7258     default:
7259       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7260     }
7261   }
7262   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7263   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7264   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7265   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7266   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7267   PetscFunctionReturn(0);
7268 }
7269 
7270 #undef __FUNCT__
7271 #define __FUNCT__ "CellRefinerCreateLabels"
7272 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7273 {
7274   PetscInt       numLabels, l;
7275   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7276   PetscErrorCode ierr;
7277 
7278   PetscFunctionBegin;
7279   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7280   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7281   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7282   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7283 
7284   cStartNew = 0;
7285   vStartNew = depthSize[2];
7286   fStartNew = depthSize[2] + depthSize[0];
7287 
7288   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7289   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7290   switch (refiner) {
7291   case 3:
7292     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7293     cMax = PetscMin(cEnd, cMax);
7294     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7295     fMax = PetscMin(fEnd, fMax);
7296   }
7297   for (l = 0; l < numLabels; ++l) {
7298     DMLabel         label, labelNew;
7299     const char     *lname;
7300     PetscBool       isDepth;
7301     IS              valueIS;
7302     const PetscInt *values;
7303     PetscInt        numValues, val;
7304 
7305     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7306     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7307     if (isDepth) continue;
7308     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7309     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7310     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7311     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7312     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7313     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7314     for (val = 0; val < numValues; ++val) {
7315       IS              pointIS;
7316       const PetscInt *points;
7317       PetscInt        numPoints, n;
7318 
7319       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7320       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7321       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7322       for (n = 0; n < numPoints; ++n) {
7323         const PetscInt p = points[n];
7324         switch (refiner) {
7325         case 1:
7326           /* Simplicial 2D */
7327           if ((p >= vStart) && (p < vEnd)) {
7328             /* Old vertices stay the same */
7329             newp = vStartNew + (p - vStart);
7330             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7331           } else if ((p >= fStart) && (p < fEnd)) {
7332             /* Old faces add new faces and vertex */
7333             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7334             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             for (r = 0; r < 2; ++r) {
7336               newp = fStartNew + (p - fStart)*2 + r;
7337               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7338             }
7339           } else if ((p >= cStart) && (p < cEnd)) {
7340             /* Old cells add new cells and interior faces */
7341             for (r = 0; r < 4; ++r) {
7342               newp = cStartNew + (p - cStart)*4 + r;
7343               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7344             }
7345             for (r = 0; r < 3; ++r) {
7346               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7347               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7348             }
7349           }
7350           break;
7351         case 2:
7352           /* Hex 2D */
7353           if ((p >= vStart) && (p < vEnd)) {
7354             /* Old vertices stay the same */
7355             newp = vStartNew + (p - vStart);
7356             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357           } else if ((p >= fStart) && (p < fEnd)) {
7358             /* Old faces add new faces and vertex */
7359             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7360             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7361             for (r = 0; r < 2; ++r) {
7362               newp = fStartNew + (p - fStart)*2 + r;
7363               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7364             }
7365           } else if ((p >= cStart) && (p < cEnd)) {
7366             /* Old cells add new cells and interior faces and vertex */
7367             for (r = 0; r < 4; ++r) {
7368               newp = cStartNew + (p - cStart)*4 + r;
7369               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7370             }
7371             for (r = 0; r < 4; ++r) {
7372               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7373               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7374             }
7375             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7376             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7377           }
7378           break;
7379         case 3:
7380           /* Hybrid simplicial 2D */
7381           if ((p >= vStart) && (p < vEnd)) {
7382             /* Old vertices stay the same */
7383             newp = vStartNew + (p - vStart);
7384             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7385           } else if ((p >= fStart) && (p < fMax)) {
7386             /* Old interior faces add new faces and vertex */
7387             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7388             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7389             for (r = 0; r < 2; ++r) {
7390               newp = fStartNew + (p - fStart)*2 + r;
7391               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7392             }
7393           } else if ((p >= fMax) && (p < fEnd)) {
7394             /* Old hybrid faces stay the same */
7395             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7396             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7397           } else if ((p >= cStart) && (p < cMax)) {
7398             /* Old interior cells add new cells and interior faces */
7399             for (r = 0; r < 4; ++r) {
7400               newp = cStartNew + (p - cStart)*4 + r;
7401               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7402             }
7403             for (r = 0; r < 3; ++r) {
7404               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7405               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7406             }
7407           } else if ((p >= cMax) && (p < cEnd)) {
7408             /* Old hybrid cells add new cells and hybrid face */
7409             for (r = 0; r < 2; ++r) {
7410               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7411               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7412             }
7413             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7414             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7415           }
7416           break;
7417         default:
7418           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7419         }
7420       }
7421       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7422       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7423     }
7424     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7425     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7426     if (0) {
7427       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7428       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7429       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7430     }
7431   }
7432   PetscFunctionReturn(0);
7433 }
7434 
7435 #undef __FUNCT__
7436 #define __FUNCT__ "DMPlexRefine_Uniform"
7437 /* This will only work for interpolated meshes */
7438 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7439 {
7440   DM             rdm;
7441   PetscInt      *depthSize;
7442   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7443   PetscErrorCode ierr;
7444 
7445   PetscFunctionBegin;
7446   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7447   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7448   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7449   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7450   /* Calculate number of new points of each depth */
7451   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7452   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7453   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7454   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7455   /* Step 1: Set chart */
7456   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7457   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7458   /* Step 2: Set cone/support sizes */
7459   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7460   /* Step 3: Setup refined DM */
7461   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7462   /* Step 4: Set cones and supports */
7463   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7464   /* Step 5: Stratify */
7465   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7466   /* Step 6: Set coordinates for vertices */
7467   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7468   /* Step 7: Create pointSF */
7469   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7470   /* Step 8: Create labels */
7471   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7472   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7473 
7474   *dmRefined = rdm;
7475   PetscFunctionReturn(0);
7476 }
7477 
7478 #undef __FUNCT__
7479 #define __FUNCT__ "DMPlexSetRefinementUniform"
7480 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7481 {
7482   DM_Plex *mesh = (DM_Plex*) dm->data;
7483 
7484   PetscFunctionBegin;
7485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7486   mesh->refinementUniform = refinementUniform;
7487   PetscFunctionReturn(0);
7488 }
7489 
7490 #undef __FUNCT__
7491 #define __FUNCT__ "DMPlexGetRefinementUniform"
7492 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7493 {
7494   DM_Plex *mesh = (DM_Plex*) dm->data;
7495 
7496   PetscFunctionBegin;
7497   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7498   PetscValidPointer(refinementUniform,  2);
7499   *refinementUniform = mesh->refinementUniform;
7500   PetscFunctionReturn(0);
7501 }
7502 
7503 #undef __FUNCT__
7504 #define __FUNCT__ "DMPlexSetRefinementLimit"
7505 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7506 {
7507   DM_Plex *mesh = (DM_Plex*) dm->data;
7508 
7509   PetscFunctionBegin;
7510   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7511   mesh->refinementLimit = refinementLimit;
7512   PetscFunctionReturn(0);
7513 }
7514 
7515 #undef __FUNCT__
7516 #define __FUNCT__ "DMPlexGetRefinementLimit"
7517 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7518 {
7519   DM_Plex *mesh = (DM_Plex*) dm->data;
7520 
7521   PetscFunctionBegin;
7522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7523   PetscValidPointer(refinementLimit,  2);
7524   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7525   *refinementLimit = mesh->refinementLimit;
7526   PetscFunctionReturn(0);
7527 }
7528 
7529 #undef __FUNCT__
7530 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7531 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7532 {
7533   PetscInt       dim, cStart, coneSize, cMax;
7534   PetscErrorCode ierr;
7535 
7536   PetscFunctionBegin;
7537   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7538   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7539   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7540   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7541   switch (dim) {
7542   case 2:
7543     switch (coneSize) {
7544     case 3:
7545       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7546       else *cellRefiner = 1; /* Triangular */
7547       break;
7548     case 4:
7549       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7550       else *cellRefiner = 2; /* Quadrilateral */
7551       break;
7552     default:
7553       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7554     }
7555     break;
7556   default:
7557     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7558   }
7559   PetscFunctionReturn(0);
7560 }
7561 
7562 #undef __FUNCT__
7563 #define __FUNCT__ "DMRefine_Plex"
7564 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7565 {
7566   PetscReal      refinementLimit;
7567   PetscInt       dim, cStart, cEnd;
7568   char           genname[1024], *name = NULL;
7569   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7570   PetscErrorCode ierr;
7571 
7572   PetscFunctionBegin;
7573   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7574   if (isUniform) {
7575     CellRefiner cellRefiner;
7576 
7577     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7578     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7579     PetscFunctionReturn(0);
7580   }
7581   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7582   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7583   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7584   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7585   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7586   if (flg) name = genname;
7587   if (name) {
7588     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7589     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7590     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7591   }
7592   switch (dim) {
7593   case 2:
7594     if (!name || isTriangle) {
7595 #if defined(PETSC_HAVE_TRIANGLE)
7596       double  *maxVolumes;
7597       PetscInt c;
7598 
7599       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7600       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7601       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7602 #else
7603       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7604 #endif
7605     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7606     break;
7607   case 3:
7608     if (!name || isCTetgen) {
7609 #if defined(PETSC_HAVE_CTETGEN)
7610       PetscReal *maxVolumes;
7611       PetscInt   c;
7612 
7613       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7614       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7615       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7616 #else
7617       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7618 #endif
7619     } else if (isTetgen) {
7620 #if defined(PETSC_HAVE_TETGEN)
7621       double  *maxVolumes;
7622       PetscInt c;
7623 
7624       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7625       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7626       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7627 #else
7628       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7629 #endif
7630     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7631     break;
7632   default:
7633     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7634   }
7635   PetscFunctionReturn(0);
7636 }
7637 
7638 #undef __FUNCT__
7639 #define __FUNCT__ "DMPlexGetDepth"
7640 /*@
7641   DMPlexGetDepth - get the number of strata
7642 
7643   Not Collective
7644 
7645   Input Parameters:
7646 . dm           - The DMPlex object
7647 
7648   Output Parameters:
7649 . depth - number of strata
7650 
7651   Level: developer
7652 
7653   Notes:
7654   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7655 
7656 .keywords: mesh, points
7657 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7658 @*/
7659 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7660 {
7661   PetscInt       d;
7662   PetscErrorCode ierr;
7663 
7664   PetscFunctionBegin;
7665   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7666   PetscValidPointer(depth, 2);
7667   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7668   *depth = d-1;
7669   PetscFunctionReturn(0);
7670 }
7671 
7672 #undef __FUNCT__
7673 #define __FUNCT__ "DMPlexGetDepthStratum"
7674 /*@
7675   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7676 
7677   Not Collective
7678 
7679   Input Parameters:
7680 + dm           - The DMPlex object
7681 - stratumValue - The requested depth
7682 
7683   Output Parameters:
7684 + start - The first point at this depth
7685 - end   - One beyond the last point at this depth
7686 
7687   Level: developer
7688 
7689 .keywords: mesh, points
7690 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7691 @*/
7692 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7693 {
7694   DM_Plex       *mesh = (DM_Plex*) dm->data;
7695   DMLabel        next  = mesh->labels;
7696   PetscBool      flg   = PETSC_FALSE;
7697   PetscInt       depth;
7698   PetscErrorCode ierr;
7699 
7700   PetscFunctionBegin;
7701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7702   if (stratumValue < 0) {
7703     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7704     PetscFunctionReturn(0);
7705   } else {
7706     PetscInt pStart, pEnd;
7707 
7708     if (start) *start = 0;
7709     if (end)   *end   = 0;
7710     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7711     if (pStart == pEnd) PetscFunctionReturn(0);
7712   }
7713   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7714   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7715   /* We should have a generic GetLabel() and a Label class */
7716   while (next) {
7717     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7718     if (flg) break;
7719     next = next->next;
7720   }
7721   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7722   depth = stratumValue;
7723   if ((depth < 0) || (depth >= next->numStrata)) {
7724     if (start) *start = 0;
7725     if (end)   *end   = 0;
7726   } else {
7727     if (start) *start = next->points[next->stratumOffsets[depth]];
7728     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7729   }
7730   PetscFunctionReturn(0);
7731 }
7732 
7733 #undef __FUNCT__
7734 #define __FUNCT__ "DMPlexGetHeightStratum"
7735 /*@
7736   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7737 
7738   Not Collective
7739 
7740   Input Parameters:
7741 + dm           - The DMPlex object
7742 - stratumValue - The requested height
7743 
7744   Output Parameters:
7745 + start - The first point at this height
7746 - end   - One beyond the last point at this height
7747 
7748   Level: developer
7749 
7750 .keywords: mesh, points
7751 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7752 @*/
7753 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7754 {
7755   DM_Plex       *mesh = (DM_Plex*) dm->data;
7756   DMLabel        next  = mesh->labels;
7757   PetscBool      flg   = PETSC_FALSE;
7758   PetscInt       depth;
7759   PetscErrorCode ierr;
7760 
7761   PetscFunctionBegin;
7762   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7763   if (stratumValue < 0) {
7764     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7765   } else {
7766     PetscInt pStart, pEnd;
7767 
7768     if (start) *start = 0;
7769     if (end)   *end   = 0;
7770     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7771     if (pStart == pEnd) PetscFunctionReturn(0);
7772   }
7773   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7774   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7775   /* We should have a generic GetLabel() and a Label class */
7776   while (next) {
7777     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7778     if (flg) break;
7779     next = next->next;
7780   }
7781   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7782   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7783   if ((depth < 0) || (depth >= next->numStrata)) {
7784     if (start) *start = 0;
7785     if (end)   *end   = 0;
7786   } else {
7787     if (start) *start = next->points[next->stratumOffsets[depth]];
7788     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7789   }
7790   PetscFunctionReturn(0);
7791 }
7792 
7793 #undef __FUNCT__
7794 #define __FUNCT__ "DMPlexCreateSectionInitial"
7795 /* Set the number of dof on each point and separate by fields */
7796 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7797 {
7798   PetscInt      *numDofTot;
7799   PetscInt       pStart = 0, pEnd = 0;
7800   PetscInt       p, d, f;
7801   PetscErrorCode ierr;
7802 
7803   PetscFunctionBegin;
7804   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7805   for (d = 0; d <= dim; ++d) {
7806     numDofTot[d] = 0;
7807     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7808   }
7809   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7810   if (numFields > 0) {
7811     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7812     if (numComp) {
7813       for (f = 0; f < numFields; ++f) {
7814         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7815       }
7816     }
7817   }
7818   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7819   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7820   for (d = 0; d <= dim; ++d) {
7821     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7822     for (p = pStart; p < pEnd; ++p) {
7823       for (f = 0; f < numFields; ++f) {
7824         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7825       }
7826       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7827     }
7828   }
7829   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7830   PetscFunctionReturn(0);
7831 }
7832 
7833 #undef __FUNCT__
7834 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7835 /* Set the number of dof on each point and separate by fields
7836    If constDof is PETSC_DETERMINE, constrain every dof on the point
7837 */
7838 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7839 {
7840   PetscInt       numFields;
7841   PetscInt       bc;
7842   PetscErrorCode ierr;
7843 
7844   PetscFunctionBegin;
7845   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7846   for (bc = 0; bc < numBC; ++bc) {
7847     PetscInt        field = 0;
7848     const PetscInt *idx;
7849     PetscInt        n, i;
7850 
7851     if (numFields) field = bcField[bc];
7852     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7853     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7854     for (i = 0; i < n; ++i) {
7855       const PetscInt p        = idx[i];
7856       PetscInt       numConst = constDof;
7857 
7858       /* Constrain every dof on the point */
7859       if (numConst < 0) {
7860         if (numFields) {
7861           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7862         } else {
7863           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7864         }
7865       }
7866       if (numFields) {
7867         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7868       }
7869       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7870     }
7871     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7872   }
7873   PetscFunctionReturn(0);
7874 }
7875 
7876 #undef __FUNCT__
7877 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7878 /* Set the constrained indices on each point and separate by fields */
7879 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7880 {
7881   PetscInt      *maxConstraints;
7882   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7883   PetscErrorCode ierr;
7884 
7885   PetscFunctionBegin;
7886   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7887   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7888   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7889   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7890   for (p = pStart; p < pEnd; ++p) {
7891     PetscInt cdof;
7892 
7893     if (numFields) {
7894       for (f = 0; f < numFields; ++f) {
7895         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7896         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7897       }
7898     } else {
7899       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7900       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7901     }
7902   }
7903   for (f = 0; f < numFields; ++f) {
7904     maxConstraints[numFields] += maxConstraints[f];
7905   }
7906   if (maxConstraints[numFields]) {
7907     PetscInt *indices;
7908 
7909     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7910     for (p = pStart; p < pEnd; ++p) {
7911       PetscInt cdof, d;
7912 
7913       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7914       if (cdof) {
7915         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7916         if (numFields) {
7917           PetscInt numConst = 0, foff = 0;
7918 
7919           for (f = 0; f < numFields; ++f) {
7920             PetscInt cfdof, fdof;
7921 
7922             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7923             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7924             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7925             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7926             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7927             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7928             numConst += cfdof;
7929             foff     += fdof;
7930           }
7931           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7932         } else {
7933           for (d = 0; d < cdof; ++d) indices[d] = d;
7934         }
7935         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7936       }
7937     }
7938     ierr = PetscFree(indices);CHKERRQ(ierr);
7939   }
7940   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7941   PetscFunctionReturn(0);
7942 }
7943 
7944 #undef __FUNCT__
7945 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7946 /* Set the constrained field indices on each point */
7947 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7948 {
7949   const PetscInt *points, *indices;
7950   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7951   PetscErrorCode  ierr;
7952 
7953   PetscFunctionBegin;
7954   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7955   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7956 
7957   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7958   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7959   if (!constraintIndices) {
7960     PetscInt *idx, i;
7961 
7962     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7963     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7964     for (i = 0; i < maxDof; ++i) idx[i] = i;
7965     for (p = 0; p < numPoints; ++p) {
7966       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7967     }
7968     ierr = PetscFree(idx);CHKERRQ(ierr);
7969   } else {
7970     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7971     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7972     for (p = 0; p < numPoints; ++p) {
7973       PetscInt fcdof;
7974 
7975       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7976       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);
7977       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7978     }
7979     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7980   }
7981   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7982   PetscFunctionReturn(0);
7983 }
7984 
7985 #undef __FUNCT__
7986 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7987 /* Set the constrained indices on each point and separate by fields */
7988 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7989 {
7990   PetscInt      *indices;
7991   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7992   PetscErrorCode ierr;
7993 
7994   PetscFunctionBegin;
7995   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7996   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7997   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7998   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7999   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8000   for (p = pStart; p < pEnd; ++p) {
8001     PetscInt cdof, d;
8002 
8003     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8004     if (cdof) {
8005       PetscInt numConst = 0, foff = 0;
8006 
8007       for (f = 0; f < numFields; ++f) {
8008         const PetscInt *fcind;
8009         PetscInt        fdof, fcdof;
8010 
8011         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8012         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8013         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8014         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8015         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8016         foff     += fdof;
8017         numConst += fcdof;
8018       }
8019       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8020       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8021     }
8022   }
8023   ierr = PetscFree(indices);CHKERRQ(ierr);
8024   PetscFunctionReturn(0);
8025 }
8026 
8027 #undef __FUNCT__
8028 #define __FUNCT__ "DMPlexCreateSection"
8029 /*@C
8030   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8031 
8032   Not Collective
8033 
8034   Input Parameters:
8035 + dm        - The DMPlex object
8036 . dim       - The spatial dimension of the problem
8037 . numFields - The number of fields in the problem
8038 . numComp   - An array of size numFields that holds the number of components for each field
8039 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8040 . numBC     - The number of boundary conditions
8041 . bcField   - An array of size numBC giving the field number for each boundry condition
8042 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8043 
8044   Output Parameter:
8045 . section - The PetscSection object
8046 
8047   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
8048   nubmer of dof for field 0 on each edge.
8049 
8050   Level: developer
8051 
8052 .keywords: mesh, elements
8053 .seealso: DMPlexCreate(), PetscSectionCreate()
8054 @*/
8055 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8056 {
8057   PetscErrorCode ierr;
8058 
8059   PetscFunctionBegin;
8060   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8061   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8062   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8063   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8064   {
8065     PetscBool view = PETSC_FALSE;
8066 
8067     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8068     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8069   }
8070   PetscFunctionReturn(0);
8071 }
8072 
8073 #undef __FUNCT__
8074 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8075 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8076 {
8077   PetscSection   section;
8078   PetscErrorCode ierr;
8079 
8080   PetscFunctionBegin;
8081   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8082   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8083   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8084   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8085   PetscFunctionReturn(0);
8086 }
8087 
8088 #undef __FUNCT__
8089 #define __FUNCT__ "DMPlexGetCoordinateSection"
8090 /*@
8091   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8092 
8093   Not Collective
8094 
8095   Input Parameter:
8096 . dm - The DMPlex object
8097 
8098   Output Parameter:
8099 . section - The PetscSection object
8100 
8101   Level: intermediate
8102 
8103 .keywords: mesh, coordinates
8104 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8105 @*/
8106 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8107 {
8108   DM             cdm;
8109   PetscErrorCode ierr;
8110 
8111   PetscFunctionBegin;
8112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8113   PetscValidPointer(section, 2);
8114   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8115   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8116   PetscFunctionReturn(0);
8117 }
8118 
8119 #undef __FUNCT__
8120 #define __FUNCT__ "DMPlexSetCoordinateSection"
8121 /*@
8122   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8123 
8124   Not Collective
8125 
8126   Input Parameters:
8127 + dm      - The DMPlex object
8128 - section - The PetscSection object
8129 
8130   Level: intermediate
8131 
8132 .keywords: mesh, coordinates
8133 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8134 @*/
8135 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8136 {
8137   DM             cdm;
8138   PetscErrorCode ierr;
8139 
8140   PetscFunctionBegin;
8141   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8142   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
8143   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8144   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8145   PetscFunctionReturn(0);
8146 }
8147 
8148 #undef __FUNCT__
8149 #define __FUNCT__ "DMPlexGetConeSection"
8150 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8151 {
8152   DM_Plex *mesh = (DM_Plex*) dm->data;
8153 
8154   PetscFunctionBegin;
8155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8156   if (section) *section = mesh->coneSection;
8157   PetscFunctionReturn(0);
8158 }
8159 
8160 #undef __FUNCT__
8161 #define __FUNCT__ "DMPlexGetCones"
8162 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8163 {
8164   DM_Plex *mesh = (DM_Plex*) dm->data;
8165 
8166   PetscFunctionBegin;
8167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8168   if (cones) *cones = mesh->cones;
8169   PetscFunctionReturn(0);
8170 }
8171 
8172 #undef __FUNCT__
8173 #define __FUNCT__ "DMPlexGetConeOrientations"
8174 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8175 {
8176   DM_Plex *mesh = (DM_Plex*) dm->data;
8177 
8178   PetscFunctionBegin;
8179   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8180   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8181   PetscFunctionReturn(0);
8182 }
8183 
8184 #undef __FUNCT__
8185 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8186 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8187 {
8188   const PetscInt embedDim = 2;
8189   PetscReal      x        = PetscRealPart(point[0]);
8190   PetscReal      y        = PetscRealPart(point[1]);
8191   PetscReal      v0[2], J[4], invJ[4], detJ;
8192   PetscReal      xi, eta;
8193   PetscErrorCode ierr;
8194 
8195   PetscFunctionBegin;
8196   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8197   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8198   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8199 
8200   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8201   else *cell = -1;
8202   PetscFunctionReturn(0);
8203 }
8204 
8205 #undef __FUNCT__
8206 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8207 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8208 {
8209   PetscSection       coordSection;
8210   Vec                coordsLocal;
8211   const PetscScalar *coords;
8212   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8213   PetscReal          x         = PetscRealPart(point[0]);
8214   PetscReal          y         = PetscRealPart(point[1]);
8215   PetscInt           crossings = 0, f;
8216   PetscErrorCode     ierr;
8217 
8218   PetscFunctionBegin;
8219   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8220   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8221   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8222   for (f = 0; f < 4; ++f) {
8223     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8224     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8225     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8226     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8227     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8228     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8229     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8230     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8231     if ((cond1 || cond2)  && above) ++crossings;
8232   }
8233   if (crossings % 2) *cell = c;
8234   else *cell = -1;
8235   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8236   PetscFunctionReturn(0);
8237 }
8238 
8239 #undef __FUNCT__
8240 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8241 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8242 {
8243   const PetscInt embedDim = 3;
8244   PetscReal      v0[3], J[9], invJ[9], detJ;
8245   PetscReal      x = PetscRealPart(point[0]);
8246   PetscReal      y = PetscRealPart(point[1]);
8247   PetscReal      z = PetscRealPart(point[2]);
8248   PetscReal      xi, eta, zeta;
8249   PetscErrorCode ierr;
8250 
8251   PetscFunctionBegin;
8252   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8253   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8254   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8255   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8256 
8257   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8258   else *cell = -1;
8259   PetscFunctionReturn(0);
8260 }
8261 
8262 #undef __FUNCT__
8263 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8264 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8265 {
8266   PetscSection       coordSection;
8267   Vec                coordsLocal;
8268   const PetscScalar *coords;
8269   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8270                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8271   PetscBool          found = PETSC_TRUE;
8272   PetscInt           f;
8273   PetscErrorCode     ierr;
8274 
8275   PetscFunctionBegin;
8276   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8277   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8278   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8279   for (f = 0; f < 6; ++f) {
8280     /* Check the point is under plane */
8281     /*   Get face normal */
8282     PetscReal v_i[3];
8283     PetscReal v_j[3];
8284     PetscReal normal[3];
8285     PetscReal pp[3];
8286     PetscReal dot;
8287 
8288     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8289     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8290     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8291     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8292     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8293     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8294     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8295     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8296     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8297     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8298     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8299     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8300     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8301 
8302     /* Check that projected point is in face (2D location problem) */
8303     if (dot < 0.0) {
8304       found = PETSC_FALSE;
8305       break;
8306     }
8307   }
8308   if (found) *cell = c;
8309   else *cell = -1;
8310   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8311   PetscFunctionReturn(0);
8312 }
8313 
8314 #undef __FUNCT__
8315 #define __FUNCT__ "DMLocatePoints_Plex"
8316 /*
8317  Need to implement using the guess
8318 */
8319 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8320 {
8321   PetscInt       cell = -1 /*, guess = -1*/;
8322   PetscInt       bs, numPoints, p;
8323   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8324   PetscInt      *cells;
8325   PetscScalar   *a;
8326   PetscErrorCode ierr;
8327 
8328   PetscFunctionBegin;
8329   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8330   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8331   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8332   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8333   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8334   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8335   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8336   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8337   numPoints /= bs;
8338   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8339   for (p = 0; p < numPoints; ++p) {
8340     const PetscScalar *point = &a[p*bs];
8341 
8342     switch (dim) {
8343     case 2:
8344       for (c = cStart; c < cEnd; ++c) {
8345         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8346         switch (coneSize) {
8347         case 3:
8348           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8349           break;
8350         case 4:
8351           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8352           break;
8353         default:
8354           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8355         }
8356         if (cell >= 0) break;
8357       }
8358       break;
8359     case 3:
8360       for (c = cStart; c < cEnd; ++c) {
8361         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8362         switch (coneSize) {
8363         case 4:
8364           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8365           break;
8366         case 8:
8367           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8368           break;
8369         default:
8370           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8371         }
8372         if (cell >= 0) break;
8373       }
8374       break;
8375     default:
8376       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8377     }
8378     cells[p] = cell;
8379   }
8380   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8381   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8382   PetscFunctionReturn(0);
8383 }
8384 
8385 /******************************** FEM Support **********************************/
8386 
8387 #undef __FUNCT__
8388 #define __FUNCT__ "DMPlexVecGetClosure"
8389 /*@C
8390   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8391 
8392   Not collective
8393 
8394   Input Parameters:
8395 + dm - The DM
8396 . section - The section describing the layout in v, or NULL to use the default section
8397 . v - The local vector
8398 - point - The sieve point in the DM
8399 
8400   Output Parameters:
8401 + csize - The number of values in the closure, or NULL
8402 - values - The array of values, which is a borrowed array and should not be freed
8403 
8404   Level: intermediate
8405 
8406 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8407 @*/
8408 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8409 {
8410   PetscScalar   *array, *vArray;
8411   PetscInt      *points = NULL;
8412   PetscInt       offsets[32];
8413   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8414   PetscErrorCode ierr;
8415 
8416   PetscFunctionBegin;
8417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8418   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8419   if (!section) {
8420     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8421   }
8422   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8423   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8424   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8425   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8426   /* Compress out points not in the section */
8427   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8428   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8429     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8430       points[q*2]   = points[p];
8431       points[q*2+1] = points[p+1];
8432       ++q;
8433     }
8434   }
8435   numPoints = q;
8436   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8437     PetscInt dof, fdof;
8438 
8439     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8440     for (f = 0; f < numFields; ++f) {
8441       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8442       offsets[f+1] += fdof;
8443     }
8444     size += dof;
8445   }
8446   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8447   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8448   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8449   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8450   for (p = 0; p < numPoints*2; p += 2) {
8451     PetscInt     o = points[p+1];
8452     PetscInt     dof, off, d;
8453     PetscScalar *varr;
8454 
8455     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8456     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8457     varr = &vArray[off];
8458     if (numFields) {
8459       PetscInt fdof, foff, fcomp, f, c;
8460 
8461       for (f = 0, foff = 0; f < numFields; ++f) {
8462         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8463         if (o >= 0) {
8464           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8465             array[offsets[f]] = varr[foff+d];
8466           }
8467         } else {
8468           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8469           for (d = fdof/fcomp-1; d >= 0; --d) {
8470             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8471               array[offsets[f]] = varr[foff+d*fcomp+c];
8472             }
8473           }
8474         }
8475         foff += fdof;
8476       }
8477     } else {
8478       if (o >= 0) {
8479         for (d = 0; d < dof; ++d, ++offsets[0]) {
8480           array[offsets[0]] = varr[d];
8481         }
8482       } else {
8483         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8484           array[offsets[0]] = varr[d];
8485         }
8486       }
8487     }
8488   }
8489   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8490   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8491   if (csize) *csize = size;
8492   *values = array;
8493   PetscFunctionReturn(0);
8494 }
8495 
8496 #undef __FUNCT__
8497 #define __FUNCT__ "DMPlexVecRestoreClosure"
8498 /*@C
8499   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8500 
8501   Not collective
8502 
8503   Input Parameters:
8504 + dm - The DM
8505 . section - The section describing the layout in v, or NULL to use the default section
8506 . v - The local vector
8507 . point - The sieve point in the DM
8508 . csize - The number of values in the closure, or NULL
8509 - values - The array of values, which is a borrowed array and should not be freed
8510 
8511   Level: intermediate
8512 
8513 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8514 @*/
8515 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8516 {
8517   PetscInt       size = 0;
8518   PetscErrorCode ierr;
8519 
8520   PetscFunctionBegin;
8521   /* Should work without recalculating size */
8522   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8523   PetscFunctionReturn(0);
8524 }
8525 
8526 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8527 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8528 
8529 #undef __FUNCT__
8530 #define __FUNCT__ "updatePoint_private"
8531 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8532 {
8533   PetscInt        cdof;   /* The number of constraints on this point */
8534   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8535   PetscScalar    *a;
8536   PetscInt        off, cind = 0, k;
8537   PetscErrorCode  ierr;
8538 
8539   PetscFunctionBegin;
8540   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8541   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8542   a    = &array[off];
8543   if (!cdof || setBC) {
8544     if (orientation >= 0) {
8545       for (k = 0; k < dof; ++k) {
8546         fuse(&a[k], values[k]);
8547       }
8548     } else {
8549       for (k = 0; k < dof; ++k) {
8550         fuse(&a[k], values[dof-k-1]);
8551       }
8552     }
8553   } else {
8554     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8555     if (orientation >= 0) {
8556       for (k = 0; k < dof; ++k) {
8557         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8558         fuse(&a[k], values[k]);
8559       }
8560     } else {
8561       for (k = 0; k < dof; ++k) {
8562         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8563         fuse(&a[k], values[dof-k-1]);
8564       }
8565     }
8566   }
8567   PetscFunctionReturn(0);
8568 }
8569 
8570 #undef __FUNCT__
8571 #define __FUNCT__ "updatePointFields_private"
8572 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8573 {
8574   PetscScalar   *a;
8575   PetscInt       numFields, off, foff, f;
8576   PetscErrorCode ierr;
8577 
8578   PetscFunctionBegin;
8579   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8580   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8581   a    = &array[off];
8582   for (f = 0, foff = 0; f < numFields; ++f) {
8583     PetscInt        fdof, fcomp, fcdof;
8584     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8585     PetscInt        cind = 0, k, c;
8586 
8587     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8588     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8589     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8590     if (!fcdof || setBC) {
8591       if (orientation >= 0) {
8592         for (k = 0; k < fdof; ++k) {
8593           fuse(&a[foff+k], values[foffs[f]+k]);
8594         }
8595       } else {
8596         for (k = fdof/fcomp-1; k >= 0; --k) {
8597           for (c = 0; c < fcomp; ++c) {
8598             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8599           }
8600         }
8601       }
8602     } else {
8603       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8604       if (orientation >= 0) {
8605         for (k = 0; k < fdof; ++k) {
8606           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8607           fuse(&a[foff+k], values[foffs[f]+k]);
8608         }
8609       } else {
8610         for (k = fdof/fcomp-1; k >= 0; --k) {
8611           for (c = 0; c < fcomp; ++c) {
8612             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8613             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8614           }
8615         }
8616       }
8617     }
8618     foff     += fdof;
8619     foffs[f] += fdof;
8620   }
8621   PetscFunctionReturn(0);
8622 }
8623 
8624 #undef __FUNCT__
8625 #define __FUNCT__ "DMPlexVecSetClosure"
8626 /*@C
8627   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8628 
8629   Not collective
8630 
8631   Input Parameters:
8632 + dm - The DM
8633 . section - The section describing the layout in v, or NULL to use the default sectionw
8634 . v - The local vector
8635 . point - The sieve point in the DM
8636 . values - The array of values, which is a borrowed array and should not be freed
8637 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8638 
8639   Level: intermediate
8640 
8641 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8642 @*/
8643 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8644 {
8645   PetscScalar   *array;
8646   PetscInt      *points = NULL;
8647   PetscInt       offsets[32];
8648   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8649   PetscErrorCode ierr;
8650 
8651   PetscFunctionBegin;
8652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8653   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8654   if (!section) {
8655     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8656   }
8657   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8658   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8659   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8660   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8661   /* Compress out points not in the section */
8662   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8663   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8664     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8665       points[q*2]   = points[p];
8666       points[q*2+1] = points[p+1];
8667       ++q;
8668     }
8669   }
8670   numPoints = q;
8671   for (p = 0; p < numPoints*2; p += 2) {
8672     PetscInt fdof;
8673 
8674     for (f = 0; f < numFields; ++f) {
8675       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8676       offsets[f+1] += fdof;
8677     }
8678   }
8679   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8680   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8681   if (numFields) {
8682     switch (mode) {
8683     case INSERT_VALUES:
8684       for (p = 0; p < numPoints*2; p += 2) {
8685         PetscInt o = points[p+1];
8686         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8687       } break;
8688     case INSERT_ALL_VALUES:
8689       for (p = 0; p < numPoints*2; p += 2) {
8690         PetscInt o = points[p+1];
8691         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8692       } break;
8693     case ADD_VALUES:
8694       for (p = 0; p < numPoints*2; p += 2) {
8695         PetscInt o = points[p+1];
8696         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8697       } break;
8698     case ADD_ALL_VALUES:
8699       for (p = 0; p < numPoints*2; p += 2) {
8700         PetscInt o = points[p+1];
8701         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8702       } break;
8703     default:
8704       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8705     }
8706   } else {
8707     switch (mode) {
8708     case INSERT_VALUES:
8709       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8710         PetscInt o = points[p+1];
8711         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8712         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8713       } break;
8714     case INSERT_ALL_VALUES:
8715       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8716         PetscInt o = points[p+1];
8717         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8718         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8719       } break;
8720     case ADD_VALUES:
8721       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8722         PetscInt o = points[p+1];
8723         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8724         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8725       } break;
8726     case ADD_ALL_VALUES:
8727       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8728         PetscInt o = points[p+1];
8729         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8730         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8731       } break;
8732     default:
8733       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8734     }
8735   }
8736   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8737   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8738   PetscFunctionReturn(0);
8739 }
8740 
8741 #undef __FUNCT__
8742 #define __FUNCT__ "DMPlexPrintMatSetValues"
8743 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8744 {
8745   PetscMPIInt    rank;
8746   PetscInt       i, j;
8747   PetscErrorCode ierr;
8748 
8749   PetscFunctionBegin;
8750   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8751   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8752   for (i = 0; i < numIndices; i++) {
8753     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8754   }
8755   for (i = 0; i < numIndices; i++) {
8756     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8757     for (j = 0; j < numIndices; j++) {
8758 #if defined(PETSC_USE_COMPLEX)
8759       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8760 #else
8761       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8762 #endif
8763     }
8764     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8765   }
8766   PetscFunctionReturn(0);
8767 }
8768 
8769 #undef __FUNCT__
8770 #define __FUNCT__ "indicesPoint_private"
8771 /* . off - The global offset of this point */
8772 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8773 {
8774   PetscInt        dof;    /* The number of unknowns on this point */
8775   PetscInt        cdof;   /* The number of constraints on this point */
8776   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8777   PetscInt        cind = 0, k;
8778   PetscErrorCode  ierr;
8779 
8780   PetscFunctionBegin;
8781   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8782   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8783   if (!cdof || setBC) {
8784     if (orientation >= 0) {
8785       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8786     } else {
8787       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8788     }
8789   } else {
8790     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8791     if (orientation >= 0) {
8792       for (k = 0; k < dof; ++k) {
8793         if ((cind < cdof) && (k == cdofs[cind])) {
8794           /* Insert check for returning constrained indices */
8795           indices[*loff+k] = -(off+k+1);
8796           ++cind;
8797         } else {
8798           indices[*loff+k] = off+k-cind;
8799         }
8800       }
8801     } else {
8802       for (k = 0; k < dof; ++k) {
8803         if ((cind < cdof) && (k == cdofs[cind])) {
8804           /* Insert check for returning constrained indices */
8805           indices[*loff+dof-k-1] = -(off+k+1);
8806           ++cind;
8807         } else {
8808           indices[*loff+dof-k-1] = off+k-cind;
8809         }
8810       }
8811     }
8812   }
8813   *loff += dof;
8814   PetscFunctionReturn(0);
8815 }
8816 
8817 #undef __FUNCT__
8818 #define __FUNCT__ "indicesPointFields_private"
8819 /* . off - The global offset of this point */
8820 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8821 {
8822   PetscInt       numFields, foff, f;
8823   PetscErrorCode ierr;
8824 
8825   PetscFunctionBegin;
8826   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8827   for (f = 0, foff = 0; f < numFields; ++f) {
8828     PetscInt        fdof, fcomp, cfdof;
8829     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8830     PetscInt        cind = 0, k, c;
8831 
8832     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8833     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8834     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8835     if (!cfdof || setBC) {
8836       if (orientation >= 0) {
8837         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8838       } else {
8839         for (k = fdof/fcomp-1; k >= 0; --k) {
8840           for (c = 0; c < fcomp; ++c) {
8841             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8842           }
8843         }
8844       }
8845     } else {
8846       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8847       if (orientation >= 0) {
8848         for (k = 0; k < fdof; ++k) {
8849           if ((cind < cfdof) && (k == fcdofs[cind])) {
8850             indices[foffs[f]+k] = -(off+foff+k+1);
8851             ++cind;
8852           } else {
8853             indices[foffs[f]+k] = off+foff+k-cind;
8854           }
8855         }
8856       } else {
8857         for (k = fdof/fcomp-1; k >= 0; --k) {
8858           for (c = 0; c < fcomp; ++c) {
8859             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8860               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8861               ++cind;
8862             } else {
8863               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8864             }
8865           }
8866         }
8867       }
8868     }
8869     foff     += fdof - cfdof;
8870     foffs[f] += fdof;
8871   }
8872   PetscFunctionReturn(0);
8873 }
8874 
8875 #undef __FUNCT__
8876 #define __FUNCT__ "DMPlexMatSetClosure"
8877 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8878 {
8879   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8880   PetscInt      *points = NULL;
8881   PetscInt      *indices;
8882   PetscInt       offsets[32];
8883   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8884   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8885   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8886   PetscErrorCode ierr;
8887 
8888   PetscFunctionBegin;
8889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8890   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8891   if (useDefault) {
8892     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8893   }
8894   if (useGlobalDefault) {
8895     if (useDefault) {
8896       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8897     } else {
8898       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8899     }
8900   }
8901   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8902   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8903   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8904   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8905   /* Compress out points not in the section */
8906   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8907   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8908     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8909       points[q*2]   = points[p];
8910       points[q*2+1] = points[p+1];
8911       ++q;
8912     }
8913   }
8914   numPoints = q;
8915   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8916     PetscInt fdof;
8917 
8918     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8919     for (f = 0; f < numFields; ++f) {
8920       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8921       offsets[f+1] += fdof;
8922     }
8923     numIndices += dof;
8924   }
8925   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8926 
8927   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8928   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8929   if (numFields) {
8930     for (p = 0; p < numPoints*2; p += 2) {
8931       PetscInt o = points[p+1];
8932       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8933       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8934     }
8935   } else {
8936     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8937       PetscInt o = points[p+1];
8938       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8939       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8940     }
8941   }
8942   if (useGlobalDefault && !useDefault) {
8943     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8944   }
8945   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8946   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8947   if (ierr) {
8948     PetscMPIInt    rank;
8949     PetscErrorCode ierr2;
8950 
8951     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8952     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8953     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8954     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8955     CHKERRQ(ierr);
8956   }
8957   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8958   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8959   PetscFunctionReturn(0);
8960 }
8961 
8962 #undef __FUNCT__
8963 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8964 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8965 {
8966   PetscSection       coordSection;
8967   Vec                coordinates;
8968   const PetscScalar *coords;
8969   const PetscInt     dim = 2;
8970   PetscInt           d, f;
8971   PetscErrorCode     ierr;
8972 
8973   PetscFunctionBegin;
8974   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8975   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8976   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8977   if (v0) {
8978     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8979   }
8980   if (J) {
8981     for (d = 0; d < dim; d++) {
8982       for (f = 0; f < dim; f++) {
8983         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8984       }
8985     }
8986     *detJ = J[0]*J[3] - J[1]*J[2];
8987 #if 0
8988     if (detJ < 0.0) {
8989       const PetscReal xLength = mesh->periodicity[0];
8990 
8991       if (xLength != 0.0) {
8992         PetscReal v0x = coords[0*dim+0];
8993 
8994         if (v0x == 0.0) v0x = v0[0] = xLength;
8995         for (f = 0; f < dim; f++) {
8996           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8997 
8998           J[0*dim+f] = 0.5*(px - v0x);
8999         }
9000       }
9001       detJ = J[0]*J[3] - J[1]*J[2];
9002     }
9003 #endif
9004     PetscLogFlops(8.0 + 3.0);
9005   }
9006   if (invJ) {
9007     const PetscReal invDet = 1.0/(*detJ);
9008 
9009     invJ[0] =  invDet*J[3];
9010     invJ[1] = -invDet*J[1];
9011     invJ[2] = -invDet*J[2];
9012     invJ[3] =  invDet*J[0];
9013     PetscLogFlops(5.0);
9014   }
9015   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9016   PetscFunctionReturn(0);
9017 }
9018 
9019 #undef __FUNCT__
9020 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9021 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9022 {
9023   PetscSection       coordSection;
9024   Vec                coordinates;
9025   const PetscScalar *coords;
9026   const PetscInt     dim = 2;
9027   PetscInt           d, f;
9028   PetscErrorCode     ierr;
9029 
9030   PetscFunctionBegin;
9031   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9032   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9033   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9034   if (v0) {
9035     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9036   }
9037   if (J) {
9038     for (d = 0; d < dim; d++) {
9039       for (f = 0; f < dim; f++) {
9040         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9041       }
9042     }
9043     *detJ = J[0]*J[3] - J[1]*J[2];
9044     PetscLogFlops(8.0 + 3.0);
9045   }
9046   if (invJ) {
9047     const PetscReal invDet = 1.0/(*detJ);
9048 
9049     invJ[0] =  invDet*J[3];
9050     invJ[1] = -invDet*J[1];
9051     invJ[2] = -invDet*J[2];
9052     invJ[3] =  invDet*J[0];
9053     PetscLogFlops(5.0);
9054   }
9055   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9056   PetscFunctionReturn(0);
9057 }
9058 
9059 #undef __FUNCT__
9060 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9061 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9062 {
9063   PetscSection       coordSection;
9064   Vec                coordinates;
9065   const PetscScalar *coords;
9066   const PetscInt     dim = 3;
9067   PetscInt           d, f;
9068   PetscErrorCode     ierr;
9069 
9070   PetscFunctionBegin;
9071   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9072   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9073   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9074   if (v0) {
9075     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9076   }
9077   if (J) {
9078     for (d = 0; d < dim; d++) {
9079       for (f = 0; f < dim; f++) {
9080         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9081       }
9082     }
9083     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9084     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9085              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9086              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9087     PetscLogFlops(18.0 + 12.0);
9088   }
9089   if (invJ) {
9090     const PetscReal invDet = 1.0/(*detJ);
9091 
9092     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9093     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9094     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9095     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9096     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9097     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9098     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9099     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9100     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9101     PetscLogFlops(37.0);
9102   }
9103   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9104   PetscFunctionReturn(0);
9105 }
9106 
9107 #undef __FUNCT__
9108 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9109 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9110 {
9111   PetscSection       coordSection;
9112   Vec                coordinates;
9113   const PetscScalar *coords;
9114   const PetscInt     dim = 3;
9115   PetscInt           d;
9116   PetscErrorCode     ierr;
9117 
9118   PetscFunctionBegin;
9119   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9120   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9121   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9122   if (v0) {
9123     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9124   }
9125   if (J) {
9126     for (d = 0; d < dim; d++) {
9127       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9128       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9129       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9130     }
9131     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9132              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9133              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9134     PetscLogFlops(18.0 + 12.0);
9135   }
9136   if (invJ) {
9137     const PetscReal invDet = -1.0/(*detJ);
9138 
9139     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9140     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9141     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9142     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9143     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9144     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9145     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9146     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9147     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9148     PetscLogFlops(37.0);
9149   }
9150   *detJ *= 8.0;
9151   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9152   PetscFunctionReturn(0);
9153 }
9154 
9155 #undef __FUNCT__
9156 #define __FUNCT__ "DMPlexComputeCellGeometry"
9157 /*@C
9158   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9159 
9160   Collective on DM
9161 
9162   Input Arguments:
9163 + dm   - the DM
9164 - cell - the cell
9165 
9166   Output Arguments:
9167 + v0   - the translation part of this affine transform
9168 . J    - the Jacobian of the transform to the reference element
9169 . invJ - the inverse of the Jacobian
9170 - detJ - the Jacobian determinant
9171 
9172   Level: advanced
9173 
9174 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9175 @*/
9176 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9177 {
9178   PetscInt       dim, coneSize;
9179   PetscErrorCode ierr;
9180 
9181   PetscFunctionBegin;
9182   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9183   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9184   switch (dim) {
9185   case 2:
9186     switch (coneSize) {
9187     case 3:
9188       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9189       break;
9190     case 4:
9191       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9192       break;
9193     default:
9194       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9195     }
9196     break;
9197   case 3:
9198     switch (coneSize) {
9199     case 4:
9200       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9201       break;
9202     case 8:
9203       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9204       break;
9205     default:
9206       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9207     }
9208     break;
9209   default:
9210     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9211   }
9212   PetscFunctionReturn(0);
9213 }
9214 
9215 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9216 {
9217   switch (i) {
9218   case 0:
9219     switch (j) {
9220     case 0: return 0;
9221     case 1:
9222       switch (k) {
9223       case 0: return 0;
9224       case 1: return 0;
9225       case 2: return 1;
9226       }
9227     case 2:
9228       switch (k) {
9229       case 0: return 0;
9230       case 1: return -1;
9231       case 2: return 0;
9232       }
9233     }
9234   case 1:
9235     switch (j) {
9236     case 0:
9237       switch (k) {
9238       case 0: return 0;
9239       case 1: return 0;
9240       case 2: return -1;
9241       }
9242     case 1: return 0;
9243     case 2:
9244       switch (k) {
9245       case 0: return 1;
9246       case 1: return 0;
9247       case 2: return 0;
9248       }
9249     }
9250   case 2:
9251     switch (j) {
9252     case 0:
9253       switch (k) {
9254       case 0: return 0;
9255       case 1: return 1;
9256       case 2: return 0;
9257       }
9258     case 1:
9259       switch (k) {
9260       case 0: return -1;
9261       case 1: return 0;
9262       case 2: return 0;
9263       }
9264     case 2: return 0;
9265     }
9266   }
9267   return 0;
9268 }
9269 
9270 #undef __FUNCT__
9271 #define __FUNCT__ "DMPlexCreateRigidBody"
9272 /*@C
9273   DMPlexCreateRigidBody - create rigid body modes from coordinates
9274 
9275   Collective on DM
9276 
9277   Input Arguments:
9278 + dm - the DM
9279 . section - the local section associated with the rigid field, or NULL for the default section
9280 - globalSection - the global section associated with the rigid field, or NULL for the default section
9281 
9282   Output Argument:
9283 . sp - the null space
9284 
9285   Note: This is necessary to take account of Dirichlet conditions on the displacements
9286 
9287   Level: advanced
9288 
9289 .seealso: MatNullSpaceCreate()
9290 @*/
9291 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9292 {
9293   MPI_Comm       comm;
9294   Vec            coordinates, localMode, mode[6];
9295   PetscSection   coordSection;
9296   PetscScalar   *coords;
9297   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9298   PetscErrorCode ierr;
9299 
9300   PetscFunctionBegin;
9301   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
9302   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9303   if (dim == 1) {
9304     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
9305     PetscFunctionReturn(0);
9306   }
9307   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9308   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9309   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9310   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9311   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9312   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9313   m    = (dim*(dim+1))/2;
9314   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9315   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9316   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9317   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9318   /* Assume P1 */
9319   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9320   for (d = 0; d < dim; ++d) {
9321     PetscScalar values[3] = {0.0, 0.0, 0.0};
9322 
9323     values[d] = 1.0;
9324     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9325     for (v = vStart; v < vEnd; ++v) {
9326       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9327     }
9328     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9329     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9330   }
9331   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9332   for (d = dim; d < dim*(dim+1)/2; ++d) {
9333     PetscInt i, j, k = dim > 2 ? d - dim : d;
9334 
9335     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9336     for (v = vStart; v < vEnd; ++v) {
9337       PetscScalar values[3] = {0.0, 0.0, 0.0};
9338       PetscInt    off;
9339 
9340       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9341       for (i = 0; i < dim; ++i) {
9342         for (j = 0; j < dim; ++j) {
9343           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9344         }
9345       }
9346       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9347     }
9348     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9349     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9350   }
9351   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9352   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9353   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9354   /* Orthonormalize system */
9355   for (i = dim; i < m; ++i) {
9356     PetscScalar dots[6];
9357 
9358     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9359     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9360     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9361     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9362   }
9363   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9364   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9365   PetscFunctionReturn(0);
9366 }
9367 
9368 #undef __FUNCT__
9369 #define __FUNCT__ "DMPlexGetHybridBounds"
9370 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9371 {
9372   DM_Plex       *mesh = (DM_Plex*) dm->data;
9373   PetscInt       dim;
9374   PetscErrorCode ierr;
9375 
9376   PetscFunctionBegin;
9377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9378   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9379   if (cMax) *cMax = mesh->hybridPointMax[dim];
9380   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9381   if (eMax) *eMax = mesh->hybridPointMax[1];
9382   if (vMax) *vMax = mesh->hybridPointMax[0];
9383   PetscFunctionReturn(0);
9384 }
9385 
9386 #undef __FUNCT__
9387 #define __FUNCT__ "DMPlexSetHybridBounds"
9388 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9389 {
9390   DM_Plex       *mesh = (DM_Plex*) dm->data;
9391   PetscInt       dim;
9392   PetscErrorCode ierr;
9393 
9394   PetscFunctionBegin;
9395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9396   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9397   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9398   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9399   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9400   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9401   PetscFunctionReturn(0);
9402 }
9403 
9404 #undef __FUNCT__
9405 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9406 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9407 {
9408   DM_Plex *mesh = (DM_Plex*) dm->data;
9409 
9410   PetscFunctionBegin;
9411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9412   PetscValidPointer(cellHeight, 2);
9413   *cellHeight = mesh->vtkCellHeight;
9414   PetscFunctionReturn(0);
9415 }
9416 
9417 #undef __FUNCT__
9418 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9419 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9420 {
9421   DM_Plex *mesh = (DM_Plex*) dm->data;
9422 
9423   PetscFunctionBegin;
9424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9425   mesh->vtkCellHeight = cellHeight;
9426   PetscFunctionReturn(0);
9427 }
9428 
9429 #undef __FUNCT__
9430 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9431 /* We can easily have a form that takes an IS instead */
9432 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9433 {
9434   PetscSection   section, globalSection;
9435   PetscInt      *numbers, p;
9436   PetscErrorCode ierr;
9437 
9438   PetscFunctionBegin;
9439   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9440   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9441   for (p = pStart; p < pEnd; ++p) {
9442     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9443   }
9444   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9445   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9446   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9447   for (p = pStart; p < pEnd; ++p) {
9448     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9449   }
9450   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9451   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9452   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9453   PetscFunctionReturn(0);
9454 }
9455 
9456 #undef __FUNCT__
9457 #define __FUNCT__ "DMPlexGetCellNumbering"
9458 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9459 {
9460   DM_Plex       *mesh = (DM_Plex*) dm->data;
9461   PetscInt       cellHeight, cStart, cEnd, cMax;
9462   PetscErrorCode ierr;
9463 
9464   PetscFunctionBegin;
9465   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9466   if (!mesh->globalCellNumbers) {
9467     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9468     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9469     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9470     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9471     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9472   }
9473   *globalCellNumbers = mesh->globalCellNumbers;
9474   PetscFunctionReturn(0);
9475 }
9476 
9477 #undef __FUNCT__
9478 #define __FUNCT__ "DMPlexGetVertexNumbering"
9479 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9480 {
9481   DM_Plex       *mesh = (DM_Plex*) dm->data;
9482   PetscInt       vStart, vEnd, vMax;
9483   PetscErrorCode ierr;
9484 
9485   PetscFunctionBegin;
9486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9487   if (!mesh->globalVertexNumbers) {
9488     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9489     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9490     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9491     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9492   }
9493   *globalVertexNumbers = mesh->globalVertexNumbers;
9494   PetscFunctionReturn(0);
9495 }
9496 
9497 #undef __FUNCT__
9498 #define __FUNCT__ "DMPlexGetScale"
9499 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9500 {
9501   DM_Plex *mesh = (DM_Plex*) dm->data;
9502 
9503   PetscFunctionBegin;
9504   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9505   PetscValidPointer(scale, 3);
9506   *scale = mesh->scale[unit];
9507   PetscFunctionReturn(0);
9508 }
9509 
9510 #undef __FUNCT__
9511 #define __FUNCT__ "DMPlexSetScale"
9512 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9513 {
9514   DM_Plex *mesh = (DM_Plex*) dm->data;
9515 
9516   PetscFunctionBegin;
9517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9518   mesh->scale[unit] = scale;
9519   PetscFunctionReturn(0);
9520 }
9521 
9522 
9523 /*******************************************************************************
9524 This should be in a separate Discretization object, but I am not sure how to lay
9525 it out yet, so I am stuffing things here while I experiment.
9526 *******************************************************************************/
9527 #undef __FUNCT__
9528 #define __FUNCT__ "DMPlexSetFEMIntegration"
9529 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9530                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9531                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9532                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9533                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9534                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9535                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9536                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9537                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9538                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9539                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9540                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9541                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9542                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9543                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9544                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9545                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9546 {
9547   DM_Plex *mesh = (DM_Plex*) dm->data;
9548 
9549   PetscFunctionBegin;
9550   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9551   mesh->integrateResidualFEM       = integrateResidualFEM;
9552   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9553   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9554   PetscFunctionReturn(0);
9555 }
9556 
9557 #undef __FUNCT__
9558 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9559 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9560 {
9561   Vec            coordinates;
9562   PetscSection   section, cSection;
9563   PetscInt       dim, vStart, vEnd, v, c, d;
9564   PetscScalar   *values, *cArray;
9565   PetscReal     *coords;
9566   PetscErrorCode ierr;
9567 
9568   PetscFunctionBegin;
9569   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9570   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9571   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9572   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9573   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9574   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9575   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9576   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9577   for (v = vStart; v < vEnd; ++v) {
9578     PetscInt dof, off;
9579 
9580     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9581     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9582     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9583     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9584     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9585     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9586   }
9587   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9588   /* Temporary, must be replaced by a projection on the finite element basis */
9589   {
9590     PetscInt eStart = 0, eEnd = 0, e, depth;
9591 
9592     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9593     --depth;
9594     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9595     for (e = eStart; e < eEnd; ++e) {
9596       const PetscInt *cone = NULL;
9597       PetscInt        coneSize, d;
9598       PetscScalar    *coordsA, *coordsB;
9599 
9600       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9601       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9602       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9603       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9604       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9605       for (d = 0; d < dim; ++d) {
9606         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9607       }
9608       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9609       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9610     }
9611   }
9612 
9613   ierr = PetscFree(coords);CHKERRQ(ierr);
9614   ierr = PetscFree(values);CHKERRQ(ierr);
9615 #if 0
9616   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9617   PetscReal      detJ;
9618 
9619   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9620   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9621   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9622 
9623   for (PetscInt c = cStart; c < cEnd; ++c) {
9624     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9625     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9626     const int                          oSize   = pV.getSize();
9627     int                                v       = 0;
9628 
9629     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9630     for (PetscInt cl = 0; cl < oSize; ++cl) {
9631       const PetscInt fDim;
9632 
9633       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9634       if (pointDim) {
9635         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9636           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9637         }
9638       }
9639     }
9640     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9641     pV.clear();
9642   }
9643   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9644   ierr = PetscFree(values);CHKERRQ(ierr);
9645 #endif
9646   PetscFunctionReturn(0);
9647 }
9648 
9649 #undef __FUNCT__
9650 #define __FUNCT__ "DMPlexProjectFunction"
9651 /*@C
9652   DMPlexProjectFunction - This projects the given function into the function space provided.
9653 
9654   Input Parameters:
9655 + dm      - The DM
9656 . numComp - The number of components (functions)
9657 . funcs   - The coordinate functions to evaluate
9658 - mode    - The insertion mode for values
9659 
9660   Output Parameter:
9661 . X - vector
9662 
9663   Level: developer
9664 
9665   Note:
9666   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9667   We will eventually fix it.
9668 
9669 ,seealso: DMPlexComputeL2Diff()
9670 */
9671 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9672 {
9673   Vec            localX;
9674   PetscErrorCode ierr;
9675 
9676   PetscFunctionBegin;
9677   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9678   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9679   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9680   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9681   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9682   PetscFunctionReturn(0);
9683 }
9684 
9685 #undef __FUNCT__
9686 #define __FUNCT__ "DMPlexComputeL2Diff"
9687 /*@C
9688   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9689 
9690   Input Parameters:
9691 + dm    - The DM
9692 . quad  - The PetscQuadrature object for each field
9693 . funcs - The functions to evaluate for each field component
9694 - X     - The coefficient vector u_h
9695 
9696   Output Parameter:
9697 . diff - The diff ||u - u_h||_2
9698 
9699   Level: developer
9700 
9701 .seealso: DMPlexProjectFunction()
9702 */
9703 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9704 {
9705   const PetscInt debug = 0;
9706   PetscSection   section;
9707   Vec            localX;
9708   PetscReal     *coords, *v0, *J, *invJ, detJ;
9709   PetscReal      localDiff = 0.0;
9710   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9711   PetscErrorCode ierr;
9712 
9713   PetscFunctionBegin;
9714   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9715   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9716   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9717   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9718   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9719   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9720   for (field = 0; field < numFields; ++field) {
9721     numComponents += quad[field].numComponents;
9722   }
9723   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9724   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9725   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9726   for (c = cStart; c < cEnd; ++c) {
9727     const PetscScalar *x;
9728     PetscReal          elemDiff = 0.0;
9729 
9730     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9731     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9732     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9733 
9734     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9735       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9736       const PetscReal *quadPoints    = quad[field].quadPoints;
9737       const PetscReal *quadWeights   = quad[field].quadWeights;
9738       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9739       const PetscInt   numBasisComps = quad[field].numComponents;
9740       const PetscReal *basis         = quad[field].basis;
9741       PetscInt         q, d, e, fc, f;
9742 
9743       if (debug) {
9744         char title[1024];
9745         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9746         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9747       }
9748       for (q = 0; q < numQuadPoints; ++q) {
9749         for (d = 0; d < dim; d++) {
9750           coords[d] = v0[d];
9751           for (e = 0; e < dim; e++) {
9752             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9753           }
9754         }
9755         for (fc = 0; fc < numBasisComps; ++fc) {
9756           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9757           PetscReal       interpolant = 0.0;
9758           for (f = 0; f < numBasisFuncs; ++f) {
9759             const PetscInt fidx = f*numBasisComps+fc;
9760             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9761           }
9762           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9763           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9764         }
9765       }
9766       comp        += numBasisComps;
9767       fieldOffset += numBasisFuncs*numBasisComps;
9768     }
9769     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9770     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9771     localDiff += elemDiff;
9772   }
9773   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9774   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9775   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9776   *diff = PetscSqrtReal(*diff);
9777   PetscFunctionReturn(0);
9778 }
9779 
9780 #undef __FUNCT__
9781 #define __FUNCT__ "DMPlexComputeResidualFEM"
9782 /*@
9783   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9784 
9785   Input Parameters:
9786 + dm - The mesh
9787 . X  - Local input vector
9788 - user - The user context
9789 
9790   Output Parameter:
9791 . F  - Local output vector
9792 
9793   Note:
9794   The second member of the user context must be an FEMContext.
9795 
9796   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9797   like a GPU, or vectorize on a multicore machine.
9798 
9799 .seealso: DMPlexComputeJacobianActionFEM()
9800 */
9801 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9802 {
9803   DM_Plex         *mesh = (DM_Plex*) dm->data;
9804   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9805   PetscQuadrature *quad = fem->quad;
9806   PetscSection     section;
9807   PetscReal       *v0, *J, *invJ, *detJ;
9808   PetscScalar     *elemVec, *u;
9809   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9810   PetscInt         cellDof = 0, numComponents = 0;
9811   PetscErrorCode   ierr;
9812 
9813   PetscFunctionBegin;
9814   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9815   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9816   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9817   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9818   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9819   numCells = cEnd - cStart;
9820   for (field = 0; field < numFields; ++field) {
9821     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9822     numComponents += quad[field].numComponents;
9823   }
9824   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9825   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9826   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9827   for (c = cStart; c < cEnd; ++c) {
9828     const PetscScalar *x;
9829     PetscInt           i;
9830 
9831     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9832     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9833     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9834 
9835     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9836     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9837   }
9838   for (field = 0; field < numFields; ++field) {
9839     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9840     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9841     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9842     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9843     /* Conforming batches */
9844     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9845     PetscInt numBlocks  = 1;
9846     PetscInt batchSize  = numBlocks * blockSize;
9847     PetscInt numBatches = numBatchesTmp;
9848     PetscInt numChunks  = numCells / (numBatches*batchSize);
9849     /* Remainder */
9850     PetscInt numRemainder = numCells % (numBatches * batchSize);
9851     PetscInt offset       = numCells - numRemainder;
9852 
9853     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9854     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9855                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9856   }
9857   for (c = cStart; c < cEnd; ++c) {
9858     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9859     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9860   }
9861   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9862   if (mesh->printFEM) {
9863     PetscMPIInt rank, numProcs;
9864     PetscInt    p;
9865 
9866     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9867     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9868     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9869     for (p = 0; p < numProcs; ++p) {
9870       if (p == rank) {
9871         Vec f;
9872 
9873         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9874         ierr = VecCopy(F, f);CHKERRQ(ierr);
9875         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9876         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9877         ierr = VecDestroy(&f);CHKERRQ(ierr);
9878         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9879       }
9880       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9881     }
9882   }
9883   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9884   PetscFunctionReturn(0);
9885 }
9886 
9887 #undef __FUNCT__
9888 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9889 /*@C
9890   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9891 
9892   Input Parameters:
9893 + dm - The mesh
9894 . J  - The Jacobian shell matrix
9895 . X  - Local input vector
9896 - user - The user context
9897 
9898   Output Parameter:
9899 . F  - Local output vector
9900 
9901   Note:
9902   The second member of the user context must be an FEMContext.
9903 
9904   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9905   like a GPU, or vectorize on a multicore machine.
9906 
9907 .seealso: DMPlexComputeResidualFEM()
9908 */
9909 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9910 {
9911   DM_Plex         *mesh = (DM_Plex*) dm->data;
9912   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9913   PetscQuadrature *quad = fem->quad;
9914   PetscSection     section;
9915   JacActionCtx    *jctx;
9916   PetscReal       *v0, *J, *invJ, *detJ;
9917   PetscScalar     *elemVec, *u, *a;
9918   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9919   PetscInt         cellDof = 0;
9920   PetscErrorCode   ierr;
9921 
9922   PetscFunctionBegin;
9923   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9924   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9925   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9926   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9927   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9928   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9929   numCells = cEnd - cStart;
9930   for (field = 0; field < numFields; ++field) {
9931     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9932   }
9933   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9934   ierr = PetscMalloc7(numCells*cellDof,PetscScalar,&u,numCells*cellDof,PetscScalar,&a,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9935   for (c = cStart; c < cEnd; ++c) {
9936     const PetscScalar *x;
9937     PetscInt           i;
9938 
9939     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9940     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9941     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9942     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9943     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9944     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9945     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9946     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9947   }
9948   for (field = 0; field < numFields; ++field) {
9949     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9950     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9951     /* Conforming batches */
9952     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9953     PetscInt numBlocks  = 1;
9954     PetscInt batchSize  = numBlocks * blockSize;
9955     PetscInt numBatches = numBatchesTmp;
9956     PetscInt numChunks  = numCells / (numBatches*batchSize);
9957     /* Remainder */
9958     PetscInt numRemainder = numCells % (numBatches * batchSize);
9959     PetscInt offset       = numCells - numRemainder;
9960 
9961     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
9962     ierr = (*mesh->integrateJacobianActionFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &a[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9963                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9964   }
9965   for (c = cStart; c < cEnd; ++c) {
9966     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9967     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9968   }
9969   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9970   if (mesh->printFEM) {
9971     PetscMPIInt rank, numProcs;
9972     PetscInt    p;
9973 
9974     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9975     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9976     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9977     for (p = 0; p < numProcs; ++p) {
9978       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9979       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9980     }
9981   }
9982   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9983   PetscFunctionReturn(0);
9984 }
9985 
9986 #undef __FUNCT__
9987 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9988 /*@
9989   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9990 
9991   Input Parameters:
9992 + dm - The mesh
9993 . X  - Local input vector
9994 - user - The user context
9995 
9996   Output Parameter:
9997 . Jac  - Jacobian matrix
9998 
9999   Note:
10000   The second member of the user context must be an FEMContext.
10001 
10002   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10003   like a GPU, or vectorize on a multicore machine.
10004 
10005 .seealso: FormFunctionLocal()
10006 */
10007 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10008 {
10009   DM_Plex         *mesh = (DM_Plex*) dm->data;
10010   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10011   PetscQuadrature *quad = fem->quad;
10012   PetscSection     section;
10013   PetscReal       *v0, *J, *invJ, *detJ;
10014   PetscScalar     *elemMat, *u;
10015   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10016   PetscInt         cellDof = 0, numComponents = 0;
10017   PetscBool        isShell;
10018   PetscErrorCode   ierr;
10019 
10020   PetscFunctionBegin;
10021   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10022   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10023   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10024   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10025   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10026   numCells = cEnd - cStart;
10027   for (field = 0; field < numFields; ++field) {
10028     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10029     numComponents += quad[field].numComponents;
10030   }
10031   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10032   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10033   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof*cellDof,PetscScalar,&elemMat);CHKERRQ(ierr);
10034   for (c = cStart; c < cEnd; ++c) {
10035     const PetscScalar *x;
10036     PetscInt           i;
10037 
10038     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10039     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10040     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10041 
10042     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10043     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10044   }
10045   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10046   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10047     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10048     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10049     PetscInt       fieldJ;
10050 
10051     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10052       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10053       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10054       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10055       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10056       /* Conforming batches */
10057       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10058       PetscInt numBlocks  = 1;
10059       PetscInt batchSize  = numBlocks * blockSize;
10060       PetscInt numBatches = numBatchesTmp;
10061       PetscInt numChunks  = numCells / (numBatches*batchSize);
10062       /* Remainder */
10063       PetscInt numRemainder = numCells % (numBatches * batchSize);
10064       PetscInt offset       = numCells - numRemainder;
10065 
10066       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10067       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10068                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10069     }
10070   }
10071   for (c = cStart; c < cEnd; ++c) {
10072     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10073     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10074   }
10075   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10076 
10077   /* Assemble matrix, using the 2-step process:
10078        MatAssemblyBegin(), MatAssemblyEnd(). */
10079   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10080   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10081 
10082   if (mesh->printFEM) {
10083     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10084     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10085     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10086   }
10087   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10088   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10089   if (isShell) {
10090     JacActionCtx *jctx;
10091 
10092     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10093     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10094   }
10095   *str = SAME_NONZERO_PATTERN;
10096   PetscFunctionReturn(0);
10097 }
10098 
10099 
10100 #undef __FUNCT__
10101 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10102 /*@C
10103   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10104   the local section and an SF describing the section point overlap.
10105 
10106   Input Parameters:
10107   + s - The PetscSection for the local field layout
10108   . sf - The SF describing parallel layout of the section points
10109   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10110   . label - The label specifying the points
10111   - labelValue - The label stratum specifying the points
10112 
10113   Output Parameter:
10114   . gsection - The PetscSection for the global field layout
10115 
10116   Note: This gives negative sizes and offsets to points not owned by this process
10117 
10118   Level: developer
10119 
10120 .seealso: PetscSectionCreate()
10121 @*/
10122 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10123 {
10124   PetscInt      *neg;
10125   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10126   PetscErrorCode ierr;
10127 
10128   PetscFunctionBegin;
10129   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10130   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10131   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10132   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10133   /* Mark ghost points with negative dof */
10134   for (p = pStart; p < pEnd; ++p) {
10135     PetscInt value;
10136 
10137     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10138     if (value != labelValue) continue;
10139     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10140     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10141     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10142     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10143     neg[p-pStart] = -(dof+1);
10144   }
10145   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10146   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
10147   if (nroots >= 0) {
10148     if (nroots > pEnd - pStart) {
10149       PetscInt *tmpDof;
10150       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10151       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10152       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10153       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10154       for (p = pStart; p < pEnd; ++p) {
10155         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
10156       }
10157       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10158     } else {
10159       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10160       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10161     }
10162   }
10163   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10164   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10165     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10166 
10167     (*gsection)->atlasOff[p] = off;
10168 
10169     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10170   }
10171   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10172   globalOff -= off;
10173   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10174     (*gsection)->atlasOff[p] += globalOff;
10175 
10176     neg[p] = -((*gsection)->atlasOff[p]+1);
10177   }
10178   /* Put in negative offsets for ghost points */
10179   if (nroots >= 0) {
10180     if (nroots > pEnd - pStart) {
10181       PetscInt *tmpOff;
10182       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10183       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10184       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10185       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10186       for (p = pStart; p < pEnd; ++p) {
10187         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
10188       }
10189       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10190     } else {
10191       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10192       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10193     }
10194   }
10195   ierr = PetscFree(neg);CHKERRQ(ierr);
10196   PetscFunctionReturn(0);
10197 }
10198