xref: /petsc/src/dm/impls/plex/plex.c (revision 5ccc9f3c757a7b48a6c5b2aabae79f8167a5150a)
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__ "DMPlexGetMaxSizes"
1700 /*@
1701   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1702 
1703   Not collective
1704 
1705   Input Parameter:
1706 . mesh - The DMPlex
1707 
1708   Output Parameters:
1709 + maxConeSize - The maximum number of in-edges
1710 - maxSupportSize - The maximum number of out-edges
1711 
1712   Level: beginner
1713 
1714 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1715 @*/
1716 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1717 {
1718   DM_Plex *mesh = (DM_Plex*) dm->data;
1719 
1720   PetscFunctionBegin;
1721   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1722   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1723   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1724   PetscFunctionReturn(0);
1725 }
1726 
1727 #undef __FUNCT__
1728 #define __FUNCT__ "DMSetUp_Plex"
1729 PetscErrorCode DMSetUp_Plex(DM dm)
1730 {
1731   DM_Plex       *mesh = (DM_Plex*) dm->data;
1732   PetscInt       size;
1733   PetscErrorCode ierr;
1734 
1735   PetscFunctionBegin;
1736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1737   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1738   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1739   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1740   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1741   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1742   if (mesh->maxSupportSize) {
1743     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1744     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1745     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1746   }
1747   PetscFunctionReturn(0);
1748 }
1749 
1750 #undef __FUNCT__
1751 #define __FUNCT__ "DMCreateSubDM_Plex"
1752 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1753 {
1754   PetscSection   section, sectionGlobal;
1755   PetscInt      *subIndices;
1756   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1757   PetscErrorCode ierr;
1758 
1759   PetscFunctionBegin;
1760   if (!numFields) PetscFunctionReturn(0);
1761   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1762   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1763   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1764   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1765   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1766   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);
1767   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1768   for (p = pStart; p < pEnd; ++p) {
1769     PetscInt gdof;
1770 
1771     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1772     if (gdof > 0) {
1773       for (f = 0; f < numFields; ++f) {
1774         PetscInt fdof, fcdof;
1775 
1776         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1777         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1778         subSize += fdof-fcdof;
1779       }
1780     }
1781   }
1782   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1783   for (p = pStart; p < pEnd; ++p) {
1784     PetscInt gdof, goff;
1785 
1786     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1787     if (gdof > 0) {
1788       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1789       for (f = 0; f < numFields; ++f) {
1790         PetscInt fdof, fcdof, fc, f2, poff = 0;
1791 
1792         /* Can get rid of this loop by storing field information in the global section */
1793         for (f2 = 0; f2 < fields[f]; ++f2) {
1794           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1795           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1796           poff += fdof-fcdof;
1797         }
1798         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1799         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1800         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1801           subIndices[subOff] = goff+poff+fc;
1802         }
1803       }
1804     }
1805   }
1806   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1807   if (subdm) {
1808     PetscSection subsection;
1809     PetscBool    haveNull = PETSC_FALSE;
1810     PetscInt     f, nf = 0;
1811 
1812     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1813     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1814     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1815     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1816     for (f = 0; f < numFields; ++f) {
1817       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1818       if ((*subdm)->nullspaceConstructors[f]) {
1819         haveNull = PETSC_TRUE;
1820         nf       = f;
1821       }
1822     }
1823     if (haveNull) {
1824       MatNullSpace nullSpace;
1825 
1826       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1827       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1828       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1829     }
1830     if (dm->fields) {
1831       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);
1832       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1833       for (f = 0; f < numFields; ++f) {
1834         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1835       }
1836       if (numFields == 1) {
1837         MatNullSpace space;
1838         Mat          pmat;
1839 
1840         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1841         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1842         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1843         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1844         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1845         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1846       }
1847     }
1848   }
1849   PetscFunctionReturn(0);
1850 }
1851 
1852 #undef __FUNCT__
1853 #define __FUNCT__ "DMPlexSymmetrize"
1854 /*@
1855   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1856 
1857   Not collective
1858 
1859   Input Parameter:
1860 . mesh - The DMPlex
1861 
1862   Output Parameter:
1863 
1864   Note:
1865   This should be called after all calls to DMPlexSetCone()
1866 
1867   Level: beginner
1868 
1869 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1870 @*/
1871 PetscErrorCode DMPlexSymmetrize(DM dm)
1872 {
1873   DM_Plex       *mesh = (DM_Plex*) dm->data;
1874   PetscInt      *offsets;
1875   PetscInt       supportSize;
1876   PetscInt       pStart, pEnd, p;
1877   PetscErrorCode ierr;
1878 
1879   PetscFunctionBegin;
1880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1881   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1882   /* Calculate support sizes */
1883   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1884   for (p = pStart; p < pEnd; ++p) {
1885     PetscInt dof, off, c;
1886 
1887     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1888     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1889     for (c = off; c < off+dof; ++c) {
1890       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1891     }
1892   }
1893   for (p = pStart; p < pEnd; ++p) {
1894     PetscInt dof;
1895 
1896     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1897 
1898     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1899   }
1900   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1901   /* Calculate supports */
1902   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1903   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1904   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1905   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1906   for (p = pStart; p < pEnd; ++p) {
1907     PetscInt dof, off, c;
1908 
1909     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1910     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1911     for (c = off; c < off+dof; ++c) {
1912       const PetscInt q = mesh->cones[c];
1913       PetscInt       offS;
1914 
1915       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1916 
1917       mesh->supports[offS+offsets[q]] = p;
1918       ++offsets[q];
1919     }
1920   }
1921   ierr = PetscFree(offsets);CHKERRQ(ierr);
1922   PetscFunctionReturn(0);
1923 }
1924 
1925 #undef __FUNCT__
1926 #define __FUNCT__ "DMPlexSetDepth_Private"
1927 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1928 {
1929   PetscInt       d;
1930   PetscErrorCode ierr;
1931 
1932   PetscFunctionBegin;
1933   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1934   if (d < 0) {
1935     /* We are guaranteed that the point has a cone since the depth was not yet set */
1936     const PetscInt *cone = NULL;
1937     PetscInt        dCone;
1938 
1939     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1940     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1941     d    = dCone+1;
1942     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1943   }
1944   *depth = d;
1945   PetscFunctionReturn(0);
1946 }
1947 
1948 #undef __FUNCT__
1949 #define __FUNCT__ "DMPlexStratify"
1950 /*@
1951   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1952   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1953   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1954   the DAG.
1955 
1956   Not collective
1957 
1958   Input Parameter:
1959 . mesh - The DMPlex
1960 
1961   Output Parameter:
1962 
1963   Notes:
1964   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1965   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1966 
1967   This should be called after all calls to DMPlexSymmetrize()
1968 
1969   Level: beginner
1970 
1971 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1972 @*/
1973 PetscErrorCode DMPlexStratify(DM dm)
1974 {
1975   DM_Plex       *mesh = (DM_Plex*) dm->data;
1976   PetscInt       pStart, pEnd, p;
1977   PetscInt       numRoots = 0, numLeaves = 0;
1978   PetscErrorCode ierr;
1979 
1980   PetscFunctionBegin;
1981   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1982   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1983   /* Calculate depth */
1984   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1985   /* Initialize roots and count leaves */
1986   for (p = pStart; p < pEnd; ++p) {
1987     PetscInt coneSize, supportSize;
1988 
1989     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1990     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1991     if (!coneSize && supportSize) {
1992       ++numRoots;
1993       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1994     } else if (!supportSize && coneSize) {
1995       ++numLeaves;
1996     } else if (!supportSize && !coneSize) {
1997       /* Isolated points */
1998       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1999     }
2000   }
2001   if (numRoots + numLeaves == (pEnd - pStart)) {
2002     for (p = pStart; p < pEnd; ++p) {
2003       PetscInt coneSize, supportSize;
2004 
2005       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2006       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2007       if (!supportSize && coneSize) {
2008         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2009       }
2010     }
2011   } else {
2012     /* This might be slow since lookup is not fast */
2013     for (p = pStart; p < pEnd; ++p) {
2014       PetscInt depth;
2015 
2016       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2017     }
2018   }
2019   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2020   PetscFunctionReturn(0);
2021 }
2022 
2023 #undef __FUNCT__
2024 #define __FUNCT__ "DMPlexGetJoin"
2025 /*@C
2026   DMPlexGetJoin - Get an array for the join of the set of points
2027 
2028   Not Collective
2029 
2030   Input Parameters:
2031 + dm - The DMPlex object
2032 . numPoints - The number of input points for the join
2033 - points - The input points
2034 
2035   Output Parameters:
2036 + numCoveredPoints - The number of points in the join
2037 - coveredPoints - The points in the join
2038 
2039   Level: intermediate
2040 
2041   Note: Currently, this is restricted to a single level join
2042 
2043 .keywords: mesh
2044 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2045 @*/
2046 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2047 {
2048   DM_Plex       *mesh = (DM_Plex*) dm->data;
2049   PetscInt      *join[2];
2050   PetscInt       joinSize, i = 0;
2051   PetscInt       dof, off, p, c, m;
2052   PetscErrorCode ierr;
2053 
2054   PetscFunctionBegin;
2055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2056   PetscValidPointer(points, 2);
2057   PetscValidPointer(numCoveredPoints, 3);
2058   PetscValidPointer(coveredPoints, 4);
2059   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2060   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2061   /* Copy in support of first point */
2062   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2063   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2064   for (joinSize = 0; joinSize < dof; ++joinSize) {
2065     join[i][joinSize] = mesh->supports[off+joinSize];
2066   }
2067   /* Check each successive support */
2068   for (p = 1; p < numPoints; ++p) {
2069     PetscInt newJoinSize = 0;
2070 
2071     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2072     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2073     for (c = 0; c < dof; ++c) {
2074       const PetscInt point = mesh->supports[off+c];
2075 
2076       for (m = 0; m < joinSize; ++m) {
2077         if (point == join[i][m]) {
2078           join[1-i][newJoinSize++] = point;
2079           break;
2080         }
2081       }
2082     }
2083     joinSize = newJoinSize;
2084     i        = 1-i;
2085   }
2086   *numCoveredPoints = joinSize;
2087   *coveredPoints    = join[i];
2088   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2089   PetscFunctionReturn(0);
2090 }
2091 
2092 #undef __FUNCT__
2093 #define __FUNCT__ "DMPlexRestoreJoin"
2094 /*@C
2095   DMPlexRestoreJoin - Restore an array for the join of the set of points
2096 
2097   Not Collective
2098 
2099   Input Parameters:
2100 + dm - The DMPlex object
2101 . numPoints - The number of input points for the join
2102 - points - The input points
2103 
2104   Output Parameters:
2105 + numCoveredPoints - The number of points in the join
2106 - coveredPoints - The points in the join
2107 
2108   Level: intermediate
2109 
2110 .keywords: mesh
2111 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2112 @*/
2113 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2114 {
2115   PetscErrorCode ierr;
2116 
2117   PetscFunctionBegin;
2118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2119   PetscValidPointer(coveredPoints, 4);
2120   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2121   PetscFunctionReturn(0);
2122 }
2123 
2124 #undef __FUNCT__
2125 #define __FUNCT__ "DMPlexGetFullJoin"
2126 /*@C
2127   DMPlexGetFullJoin - Get an array for the join of the set of points
2128 
2129   Not Collective
2130 
2131   Input Parameters:
2132 + dm - The DMPlex object
2133 . numPoints - The number of input points for the join
2134 - points - The input points
2135 
2136   Output Parameters:
2137 + numCoveredPoints - The number of points in the join
2138 - coveredPoints - The points in the join
2139 
2140   Level: intermediate
2141 
2142 .keywords: mesh
2143 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2144 @*/
2145 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2146 {
2147   DM_Plex       *mesh = (DM_Plex*) dm->data;
2148   PetscInt      *offsets, **closures;
2149   PetscInt      *join[2];
2150   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2151   PetscInt       p, d, c, m;
2152   PetscErrorCode ierr;
2153 
2154   PetscFunctionBegin;
2155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2156   PetscValidPointer(points, 2);
2157   PetscValidPointer(numCoveredPoints, 3);
2158   PetscValidPointer(coveredPoints, 4);
2159 
2160   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2161   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2162   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2163   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2164   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2165   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2166   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2167 
2168   for (p = 0; p < numPoints; ++p) {
2169     PetscInt closureSize;
2170 
2171     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2172 
2173     offsets[p*(depth+2)+0] = 0;
2174     for (d = 0; d < depth+1; ++d) {
2175       PetscInt pStart, pEnd, i;
2176 
2177       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2178       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2179         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2180           offsets[p*(depth+2)+d+1] = i;
2181           break;
2182         }
2183       }
2184       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2185     }
2186     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);
2187   }
2188   for (d = 0; d < depth+1; ++d) {
2189     PetscInt dof;
2190 
2191     /* Copy in support of first point */
2192     dof = offsets[d+1] - offsets[d];
2193     for (joinSize = 0; joinSize < dof; ++joinSize) {
2194       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2195     }
2196     /* Check each successive cone */
2197     for (p = 1; p < numPoints && joinSize; ++p) {
2198       PetscInt newJoinSize = 0;
2199 
2200       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2201       for (c = 0; c < dof; ++c) {
2202         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2203 
2204         for (m = 0; m < joinSize; ++m) {
2205           if (point == join[i][m]) {
2206             join[1-i][newJoinSize++] = point;
2207             break;
2208           }
2209         }
2210       }
2211       joinSize = newJoinSize;
2212       i        = 1-i;
2213     }
2214     if (joinSize) break;
2215   }
2216   *numCoveredPoints = joinSize;
2217   *coveredPoints    = join[i];
2218   for (p = 0; p < numPoints; ++p) {
2219     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2220   }
2221   ierr = PetscFree(closures);CHKERRQ(ierr);
2222   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2223   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2224   PetscFunctionReturn(0);
2225 }
2226 
2227 #undef __FUNCT__
2228 #define __FUNCT__ "DMPlexGetMeet"
2229 /*@C
2230   DMPlexGetMeet - Get an array for the meet of the set of points
2231 
2232   Not Collective
2233 
2234   Input Parameters:
2235 + dm - The DMPlex object
2236 . numPoints - The number of input points for the meet
2237 - points - The input points
2238 
2239   Output Parameters:
2240 + numCoveredPoints - The number of points in the meet
2241 - coveredPoints - The points in the meet
2242 
2243   Level: intermediate
2244 
2245   Note: Currently, this is restricted to a single level meet
2246 
2247 .keywords: mesh
2248 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2249 @*/
2250 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2251 {
2252   DM_Plex       *mesh = (DM_Plex*) dm->data;
2253   PetscInt      *meet[2];
2254   PetscInt       meetSize, i = 0;
2255   PetscInt       dof, off, p, c, m;
2256   PetscErrorCode ierr;
2257 
2258   PetscFunctionBegin;
2259   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2260   PetscValidPointer(points, 2);
2261   PetscValidPointer(numCoveringPoints, 3);
2262   PetscValidPointer(coveringPoints, 4);
2263   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2264   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2265   /* Copy in cone of first point */
2266   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2267   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2268   for (meetSize = 0; meetSize < dof; ++meetSize) {
2269     meet[i][meetSize] = mesh->cones[off+meetSize];
2270   }
2271   /* Check each successive cone */
2272   for (p = 1; p < numPoints; ++p) {
2273     PetscInt newMeetSize = 0;
2274 
2275     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2276     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2277     for (c = 0; c < dof; ++c) {
2278       const PetscInt point = mesh->cones[off+c];
2279 
2280       for (m = 0; m < meetSize; ++m) {
2281         if (point == meet[i][m]) {
2282           meet[1-i][newMeetSize++] = point;
2283           break;
2284         }
2285       }
2286     }
2287     meetSize = newMeetSize;
2288     i        = 1-i;
2289   }
2290   *numCoveringPoints = meetSize;
2291   *coveringPoints    = meet[i];
2292   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2293   PetscFunctionReturn(0);
2294 }
2295 
2296 #undef __FUNCT__
2297 #define __FUNCT__ "DMPlexRestoreMeet"
2298 /*@C
2299   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2300 
2301   Not Collective
2302 
2303   Input Parameters:
2304 + dm - The DMPlex object
2305 . numPoints - The number of input points for the meet
2306 - points - The input points
2307 
2308   Output Parameters:
2309 + numCoveredPoints - The number of points in the meet
2310 - coveredPoints - The points in the meet
2311 
2312   Level: intermediate
2313 
2314 .keywords: mesh
2315 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2316 @*/
2317 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2318 {
2319   PetscErrorCode ierr;
2320 
2321   PetscFunctionBegin;
2322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2323   PetscValidPointer(coveredPoints, 4);
2324   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2325   PetscFunctionReturn(0);
2326 }
2327 
2328 #undef __FUNCT__
2329 #define __FUNCT__ "DMPlexGetFullMeet"
2330 /*@C
2331   DMPlexGetFullMeet - Get an array for the meet of the set of points
2332 
2333   Not Collective
2334 
2335   Input Parameters:
2336 + dm - The DMPlex object
2337 . numPoints - The number of input points for the meet
2338 - points - The input points
2339 
2340   Output Parameters:
2341 + numCoveredPoints - The number of points in the meet
2342 - coveredPoints - The points in the meet
2343 
2344   Level: intermediate
2345 
2346 .keywords: mesh
2347 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2348 @*/
2349 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2350 {
2351   DM_Plex       *mesh = (DM_Plex*) dm->data;
2352   PetscInt      *offsets, **closures;
2353   PetscInt      *meet[2];
2354   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2355   PetscInt       p, h, c, m;
2356   PetscErrorCode ierr;
2357 
2358   PetscFunctionBegin;
2359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2360   PetscValidPointer(points, 2);
2361   PetscValidPointer(numCoveredPoints, 3);
2362   PetscValidPointer(coveredPoints, 4);
2363 
2364   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2365   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2366   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2367   maxSize = PetscPowInt(mesh->maxConeSize,height);
2368   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2369   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2370 
2371   for (p = 0; p < numPoints; ++p) {
2372     PetscInt closureSize;
2373 
2374     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2375 
2376     offsets[p*(height+2)+0] = 0;
2377     for (h = 0; h < height+1; ++h) {
2378       PetscInt pStart, pEnd, i;
2379 
2380       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2381       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2382         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2383           offsets[p*(height+2)+h+1] = i;
2384           break;
2385         }
2386       }
2387       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2388     }
2389     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);
2390   }
2391   for (h = 0; h < height+1; ++h) {
2392     PetscInt dof;
2393 
2394     /* Copy in cone of first point */
2395     dof = offsets[h+1] - offsets[h];
2396     for (meetSize = 0; meetSize < dof; ++meetSize) {
2397       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2398     }
2399     /* Check each successive cone */
2400     for (p = 1; p < numPoints && meetSize; ++p) {
2401       PetscInt newMeetSize = 0;
2402 
2403       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2404       for (c = 0; c < dof; ++c) {
2405         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2406 
2407         for (m = 0; m < meetSize; ++m) {
2408           if (point == meet[i][m]) {
2409             meet[1-i][newMeetSize++] = point;
2410             break;
2411           }
2412         }
2413       }
2414       meetSize = newMeetSize;
2415       i        = 1-i;
2416     }
2417     if (meetSize) break;
2418   }
2419   *numCoveredPoints = meetSize;
2420   *coveredPoints    = meet[i];
2421   for (p = 0; p < numPoints; ++p) {
2422     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2423   }
2424   ierr = PetscFree(closures);CHKERRQ(ierr);
2425   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2426   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2427   PetscFunctionReturn(0);
2428 }
2429 
2430 #undef __FUNCT__
2431 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2432 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2433 {
2434   MPI_Comm       comm;
2435   PetscInt       cellDim;
2436   PetscErrorCode ierr;
2437 
2438   PetscFunctionBegin;
2439   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2440   PetscValidPointer(numFaceVertices,3);
2441   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2442   switch (cellDim) {
2443   case 0:
2444     *numFaceVertices = 0;
2445     break;
2446   case 1:
2447     *numFaceVertices = 1;
2448     break;
2449   case 2:
2450     switch (numCorners) {
2451     case 3: /* triangle */
2452       *numFaceVertices = 2; /* Edge has 2 vertices */
2453       break;
2454     case 4: /* quadrilateral */
2455       *numFaceVertices = 2; /* Edge has 2 vertices */
2456       break;
2457     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2458       *numFaceVertices = 3; /* Edge has 3 vertices */
2459       break;
2460     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2461       *numFaceVertices = 3; /* Edge has 3 vertices */
2462       break;
2463     default:
2464       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2465     }
2466     break;
2467   case 3:
2468     switch (numCorners) {
2469     case 4: /* tetradehdron */
2470       *numFaceVertices = 3; /* Face has 3 vertices */
2471       break;
2472     case 6: /* tet cohesive cells */
2473       *numFaceVertices = 4; /* Face has 4 vertices */
2474       break;
2475     case 8: /* hexahedron */
2476       *numFaceVertices = 4; /* Face has 4 vertices */
2477       break;
2478     case 9: /* tet cohesive Lagrange cells */
2479       *numFaceVertices = 6; /* Face has 6 vertices */
2480       break;
2481     case 10: /* quadratic tetrahedron */
2482       *numFaceVertices = 6; /* Face has 6 vertices */
2483       break;
2484     case 12: /* hex cohesive Lagrange cells */
2485       *numFaceVertices = 6; /* Face has 6 vertices */
2486       break;
2487     case 18: /* quadratic tet cohesive Lagrange cells */
2488       *numFaceVertices = 6; /* Face has 6 vertices */
2489       break;
2490     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2491       *numFaceVertices = 9; /* Face has 9 vertices */
2492       break;
2493     default:
2494       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2495     }
2496     break;
2497   default:
2498     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2499   }
2500   PetscFunctionReturn(0);
2501 }
2502 
2503 #undef __FUNCT__
2504 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2505 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2506 {
2507   const PetscInt maxFaceCases = 30;
2508   PetscInt       numFaceCases = 0;
2509   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2510   PetscInt      *off, *adj;
2511   PetscInt      *neighborCells, *tmpClosure;
2512   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2513   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2514   PetscErrorCode ierr;
2515 
2516   PetscFunctionBegin;
2517   /* For parallel partitioning, I think you have to communicate supports */
2518   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2519   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2520   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2521   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2522   if (cEnd - cStart == 0) {
2523     if (numVertices) *numVertices = 0;
2524     if (offsets)   *offsets   = NULL;
2525     if (adjacency) *adjacency = NULL;
2526     PetscFunctionReturn(0);
2527   }
2528   numCells = cEnd - cStart;
2529   /* Setup face recognition */
2530   if (depth == 1) {
2531     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 */
2532 
2533     for (c = cStart; c < cEnd; ++c) {
2534       PetscInt corners;
2535 
2536       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2537       if (!cornersSeen[corners]) {
2538         PetscInt nFV;
2539 
2540         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2541         cornersSeen[corners] = 1;
2542 
2543         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2544 
2545         numFaceVertices[numFaceCases++] = nFV;
2546       }
2547     }
2548   }
2549   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2550   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2551   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2552   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2553   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2554   /* Count neighboring cells */
2555   for (cell = cStart; cell < cEnd; ++cell) {
2556     PetscInt numNeighbors = maxNeighbors, n;
2557 
2558     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2559     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2560     for (n = 0; n < numNeighbors; ++n) {
2561       PetscInt        cellPair[2];
2562       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2563       PetscInt        meetSize = 0;
2564       const PetscInt *meet    = NULL;
2565 
2566       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2567       if (cellPair[0] == cellPair[1]) continue;
2568       if (!found) {
2569         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2570         if (meetSize) {
2571           PetscInt f;
2572 
2573           for (f = 0; f < numFaceCases; ++f) {
2574             if (numFaceVertices[f] == meetSize) {
2575               found = PETSC_TRUE;
2576               break;
2577             }
2578           }
2579         }
2580         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2581       }
2582       if (found) ++off[cell-cStart+1];
2583     }
2584   }
2585   /* Prefix sum */
2586   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2587 
2588   if (adjacency) {
2589     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2590     /* Get neighboring cells */
2591     for (cell = cStart; cell < cEnd; ++cell) {
2592       PetscInt numNeighbors = maxNeighbors, n;
2593       PetscInt cellOffset   = 0;
2594 
2595       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2596       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2597       for (n = 0; n < numNeighbors; ++n) {
2598         PetscInt        cellPair[2];
2599         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2600         PetscInt        meetSize = 0;
2601         const PetscInt *meet    = NULL;
2602 
2603         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2604         if (cellPair[0] == cellPair[1]) continue;
2605         if (!found) {
2606           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2607           if (meetSize) {
2608             PetscInt f;
2609 
2610             for (f = 0; f < numFaceCases; ++f) {
2611               if (numFaceVertices[f] == meetSize) {
2612                 found = PETSC_TRUE;
2613                 break;
2614               }
2615             }
2616           }
2617           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2618         }
2619         if (found) {
2620           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2621           ++cellOffset;
2622         }
2623       }
2624     }
2625   }
2626   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2627   if (numVertices) *numVertices = numCells;
2628   if (offsets)   *offsets   = off;
2629   if (adjacency) *adjacency = adj;
2630   PetscFunctionReturn(0);
2631 }
2632 
2633 #if defined(PETSC_HAVE_CHACO)
2634 #if defined(PETSC_HAVE_UNISTD_H)
2635 #include <unistd.h>
2636 #endif
2637 /* Chaco does not have an include file */
2638 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2639                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2640                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2641                        int mesh_dims[3], double *goal, int global_method, int local_method,
2642                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2643 
2644 extern int FREE_GRAPH;
2645 
2646 #undef __FUNCT__
2647 #define __FUNCT__ "DMPlexPartition_Chaco"
2648 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2649 {
2650   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2651   MPI_Comm       comm;
2652   int            nvtxs          = numVertices; /* number of vertices in full graph */
2653   int           *vwgts          = NULL;   /* weights for all vertices */
2654   float         *ewgts          = NULL;   /* weights for all edges */
2655   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2656   char          *outassignname  = NULL;   /*  name of assignment output file */
2657   char          *outfilename    = NULL;   /* output file name */
2658   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2659   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2660   int            mesh_dims[3];            /* dimensions of mesh of processors */
2661   double        *goal          = NULL;    /* desired set sizes for each set */
2662   int            global_method = 1;       /* global partitioning algorithm */
2663   int            local_method  = 1;       /* local partitioning algorithm */
2664   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2665   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2666   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2667   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2668   long           seed          = 123636512; /* for random graph mutations */
2669   short int     *assignment;              /* Output partition */
2670   int            fd_stdout, fd_pipe[2];
2671   PetscInt      *points;
2672   PetscMPIInt    commSize;
2673   int            i, v, p;
2674   PetscErrorCode ierr;
2675 
2676   PetscFunctionBegin;
2677   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2678   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2679   if (!numVertices) {
2680     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2681     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2682     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2683     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2684     PetscFunctionReturn(0);
2685   }
2686   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2687   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2688 
2689   if (global_method == INERTIAL_METHOD) {
2690     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2691     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2692   }
2693   mesh_dims[0] = commSize;
2694   mesh_dims[1] = 1;
2695   mesh_dims[2] = 1;
2696   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2697   /* Chaco outputs to stdout. We redirect this to a buffer. */
2698   /* TODO: check error codes for UNIX calls */
2699 #if defined(PETSC_HAVE_UNISTD_H)
2700   {
2701     int piperet;
2702     piperet = pipe(fd_pipe);
2703     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2704     fd_stdout = dup(1);
2705     close(1);
2706     dup2(fd_pipe[1], 1);
2707   }
2708 #endif
2709   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2710                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2711                    vmax, ndims, eigtol, seed);
2712 #if defined(PETSC_HAVE_UNISTD_H)
2713   {
2714     char msgLog[10000];
2715     int  count;
2716 
2717     fflush(stdout);
2718     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2719     if (count < 0) count = 0;
2720     msgLog[count] = 0;
2721     close(1);
2722     dup2(fd_stdout, 1);
2723     close(fd_stdout);
2724     close(fd_pipe[0]);
2725     close(fd_pipe[1]);
2726     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2727   }
2728 #endif
2729   /* Convert to PetscSection+IS */
2730   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2731   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2732   for (v = 0; v < nvtxs; ++v) {
2733     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2734   }
2735   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2736   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2737   for (p = 0, i = 0; p < commSize; ++p) {
2738     for (v = 0; v < nvtxs; ++v) {
2739       if (assignment[v] == p) points[i++] = v;
2740     }
2741   }
2742   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2743   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2744   if (global_method == INERTIAL_METHOD) {
2745     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2746   }
2747   ierr = PetscFree(assignment);CHKERRQ(ierr);
2748   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2749   PetscFunctionReturn(0);
2750 }
2751 #endif
2752 
2753 #if defined(PETSC_HAVE_PARMETIS)
2754 #undef __FUNCT__
2755 #define __FUNCT__ "DMPlexPartition_ParMetis"
2756 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2757 {
2758   PetscFunctionBegin;
2759   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2760   PetscFunctionReturn(0);
2761 }
2762 #endif
2763 
2764 #undef __FUNCT__
2765 #define __FUNCT__ "DMPlexEnlargePartition"
2766 /* Expand the partition by BFS on the adjacency graph */
2767 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2768 {
2769   PetscHashI      h;
2770   const PetscInt *points;
2771   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2772   PetscInt        pStart, pEnd, part, q;
2773   PetscErrorCode  ierr;
2774 
2775   PetscFunctionBegin;
2776   PetscHashICreate(h);
2777   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2778   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2779   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2780   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2781   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2782   for (part = pStart; part < pEnd; ++part) {
2783     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2784 
2785     PetscHashIClear(h);
2786     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2787     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2788     /* Add all existing points to h */
2789     for (p = 0; p < numPoints; ++p) {
2790       const PetscInt point = points[off+p];
2791       PetscHashIAdd(h, point, 1);
2792     }
2793     PetscHashISize(h, nP);
2794     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2795     /* Add all points in next BFS level */
2796     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2797     for (p = 0; p < numPoints; ++p) {
2798       const PetscInt point = points[off+p];
2799       PetscInt       s     = start[point], e = start[point+1], a;
2800 
2801       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2802     }
2803     PetscHashISize(h, numNewPoints);
2804     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2805     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2806     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2807     totPoints += numNewPoints;
2808   }
2809   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2810   PetscHashIDestroy(h);
2811   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2812   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2813   for (part = pStart, q = 0; part < pEnd; ++part) {
2814     PetscInt numPoints, p;
2815 
2816     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2817     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2818     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2819   }
2820   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2821   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2822   PetscFunctionReturn(0);
2823 }
2824 
2825 #undef __FUNCT__
2826 #define __FUNCT__ "DMPlexCreatePartition"
2827 /*
2828   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2829 
2830   Collective on DM
2831 
2832   Input Parameters:
2833   + dm - The DM
2834   . height - The height for points in the partition
2835   - enlarge - Expand each partition with neighbors
2836 
2837   Output Parameters:
2838   + partSection - The PetscSection giving the division of points by partition
2839   . partition - The list of points by partition
2840   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2841   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2842 
2843   Level: developer
2844 
2845 .seealso DMPlexDistribute()
2846 */
2847 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2848 {
2849   PetscMPIInt    size;
2850   PetscErrorCode ierr;
2851 
2852   PetscFunctionBegin;
2853   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2854 
2855   *origPartSection = NULL;
2856   *origPartition   = NULL;
2857   if (size == 1) {
2858     PetscInt *points;
2859     PetscInt  cStart, cEnd, c;
2860 
2861     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2862     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2863     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2864     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2865     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2866     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2867     for (c = cStart; c < cEnd; ++c) points[c] = c;
2868     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2869     PetscFunctionReturn(0);
2870   }
2871   if (height == 0) {
2872     PetscInt  numVertices;
2873     PetscInt *start     = NULL;
2874     PetscInt *adjacency = NULL;
2875 
2876     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2877     if (1) {
2878 #if defined(PETSC_HAVE_CHACO)
2879       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2880 #endif
2881     } else {
2882 #if defined(PETSC_HAVE_PARMETIS)
2883       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2884 #endif
2885     }
2886     if (enlarge) {
2887       *origPartSection = *partSection;
2888       *origPartition   = *partition;
2889 
2890       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2891     }
2892     ierr = PetscFree(start);CHKERRQ(ierr);
2893     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2894 # if 0
2895   } else if (height == 1) {
2896     /* Build the dual graph for faces and partition the hypergraph */
2897     PetscInt numEdges;
2898 
2899     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2900     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2901     destroyCSR(numEdges, start, adjacency);
2902 #endif
2903   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2904   PetscFunctionReturn(0);
2905 }
2906 
2907 #undef __FUNCT__
2908 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2909 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2910 {
2911   /* const PetscInt  height = 0; */
2912   const PetscInt *partArray;
2913   PetscInt       *allPoints, *partPoints = NULL;
2914   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2915   PetscErrorCode  ierr;
2916 
2917   PetscFunctionBegin;
2918   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2919   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2920   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2921   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2922   for (rank = rStart; rank < rEnd; ++rank) {
2923     PetscInt partSize = 0;
2924     PetscInt numPoints, offset, p;
2925 
2926     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2927     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2928     for (p = 0; p < numPoints; ++p) {
2929       PetscInt  point   = partArray[offset+p], closureSize, c;
2930       PetscInt *closure = NULL;
2931 
2932       /* TODO Include support for height > 0 case */
2933       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2934       /* Merge into existing points */
2935       if (partSize+closureSize > maxPartSize) {
2936         PetscInt *tmpPoints;
2937 
2938         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2939         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2940         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2941         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2942 
2943         partPoints = tmpPoints;
2944       }
2945       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2946       partSize += closureSize;
2947 
2948       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2949       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2950     }
2951     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2952   }
2953   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2954   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2955   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2956 
2957   for (rank = rStart; rank < rEnd; ++rank) {
2958     PetscInt partSize = 0, newOffset;
2959     PetscInt numPoints, offset, p;
2960 
2961     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2962     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2963     for (p = 0; p < numPoints; ++p) {
2964       PetscInt  point   = partArray[offset+p], closureSize, c;
2965       PetscInt *closure = NULL;
2966 
2967       /* TODO Include support for height > 0 case */
2968       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2969       /* Merge into existing points */
2970       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2971       partSize += closureSize;
2972 
2973       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2974       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2975     }
2976     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
2977     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2978   }
2979   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2980   ierr = PetscFree(partPoints);CHKERRQ(ierr);
2981   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2982   PetscFunctionReturn(0);
2983 }
2984 
2985 #undef __FUNCT__
2986 #define __FUNCT__ "DMPlexDistributeField"
2987 /*
2988   Input Parameters:
2989 . originalSection
2990 , originalVec
2991 
2992   Output Parameters:
2993 . newSection
2994 . newVec
2995 */
2996 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2997 {
2998   PetscSF        fieldSF;
2999   PetscInt      *remoteOffsets, fieldSize;
3000   PetscScalar   *originalValues, *newValues;
3001   PetscErrorCode ierr;
3002 
3003   PetscFunctionBegin;
3004   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3005 
3006   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3007   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3008   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3009 
3010   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3011   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3012   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3013   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3014   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3015   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3016   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3017   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3018   PetscFunctionReturn(0);
3019 }
3020 
3021 #undef __FUNCT__
3022 #define __FUNCT__ "DMPlexDistribute"
3023 /*@C
3024   DMPlexDistribute - Distributes the mesh and any associated sections.
3025 
3026   Not Collective
3027 
3028   Input Parameter:
3029 + dm  - The original DMPlex object
3030 . partitioner - The partitioning package, or NULL for the default
3031 - overlap - The overlap of partitions, 0 is the default
3032 
3033   Output Parameter:
3034 . parallelMesh - The distributed DMPlex object, or NULL
3035 
3036   Note: If the mesh was not distributed, the return value is NULL
3037 
3038   Level: intermediate
3039 
3040 .keywords: mesh, elements
3041 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3042 @*/
3043 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3044 {
3045   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3046   MPI_Comm               comm;
3047   const PetscInt         height = 0;
3048   PetscInt               dim, numRemoteRanks;
3049   IS                     origCellPart,        cellPart,        part;
3050   PetscSection           origCellPartSection, cellPartSection, partSection;
3051   PetscSFNode           *remoteRanks;
3052   PetscSF                partSF, pointSF, coneSF;
3053   ISLocalToGlobalMapping renumbering;
3054   PetscSection           originalConeSection, newConeSection;
3055   PetscInt              *remoteOffsets;
3056   PetscInt              *cones, *newCones, newConesSize;
3057   PetscBool              flg;
3058   PetscMPIInt            rank, numProcs, p;
3059   PetscErrorCode         ierr;
3060 
3061   PetscFunctionBegin;
3062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3063   PetscValidPointer(dmParallel,4);
3064 
3065   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3066   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3067   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3068   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3069 
3070   *dmParallel = NULL;
3071   if (numProcs == 1) PetscFunctionReturn(0);
3072 
3073   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3074   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3075   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3076   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3077   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3078   if (!rank) numRemoteRanks = numProcs;
3079   else       numRemoteRanks = 0;
3080   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3081   for (p = 0; p < numRemoteRanks; ++p) {
3082     remoteRanks[p].rank  = p;
3083     remoteRanks[p].index = 0;
3084   }
3085   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3086   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3087   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3088   if (flg) {
3089     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3090     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3091     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3092     if (origCellPart) {
3093       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3094       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3095       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3096     }
3097     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3098   }
3099   /* Close the partition over the mesh */
3100   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3101   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3102   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3103   /* Create new mesh */
3104   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3105   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3106   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3107   pmesh = (DM_Plex*) (*dmParallel)->data;
3108   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3109   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3110   if (flg) {
3111     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3112     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3113     ierr = ISView(part, NULL);CHKERRQ(ierr);
3114     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3115     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3116     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3117   }
3118   /* Distribute cone section */
3119   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3120   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3121   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3122   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3123   {
3124     PetscInt pStart, pEnd, p;
3125 
3126     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3127     for (p = pStart; p < pEnd; ++p) {
3128       PetscInt coneSize;
3129       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3130       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3131     }
3132   }
3133   /* Communicate and renumber cones */
3134   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3135   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3136   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3137   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3138   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3139   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3140   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3141   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3142   if (flg) {
3143     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3144     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3145     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3148   }
3149   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3150   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3151   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3152   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3153   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3154   /* Create supports and stratify sieve */
3155   {
3156     PetscInt pStart, pEnd;
3157 
3158     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3159     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3160   }
3161   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3162   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3163   /* Distribute Coordinates */
3164   {
3165     PetscSection originalCoordSection, newCoordSection;
3166     Vec          originalCoordinates, newCoordinates;
3167     const char  *name;
3168 
3169     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3170     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3171     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3172     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3173     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3174     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3175 
3176     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3177     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3178     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3179   }
3180   /* Distribute labels */
3181   {
3182     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3183     PetscInt numLabels = 0, l;
3184 
3185     /* Bcast number of labels */
3186     while (next) {
3187       ++numLabels; next = next->next;
3188     }
3189     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3190     next = mesh->labels;
3191     for (l = 0; l < numLabels; ++l) {
3192       DMLabel         newLabel;
3193       const PetscInt *partArray;
3194       char           *name;
3195       PetscInt       *stratumSizes = NULL, *points = NULL;
3196       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3197       PetscInt        nameSize, s, p;
3198       PetscBool       isdepth;
3199       size_t          len = 0;
3200 
3201       /* Bcast name (could filter for no points) */
3202       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3203       nameSize = len;
3204       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3205       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3206       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3207       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3208       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3209       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3210       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3211       newLabel->name = name;
3212       /* Bcast numStrata (could filter for no points in stratum) */
3213       if (!rank) newLabel->numStrata = next->numStrata;
3214       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3215       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3216                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3217                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3218       /* Bcast stratumValues (could filter for no points in stratum) */
3219       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3220       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3221       /* Find size on each process and Scatter */
3222       if (!rank) {
3223         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3224         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3225         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3226         for (s = 0; s < next->numStrata; ++s) {
3227           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3228             const PetscInt point = next->points[p];
3229             PetscInt       proc;
3230 
3231             for (proc = 0; proc < numProcs; ++proc) {
3232               PetscInt dof, off, pPart;
3233 
3234               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3235               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3236               for (pPart = off; pPart < off+dof; ++pPart) {
3237                 if (partArray[pPart] == point) {
3238                   ++stratumSizes[proc*next->numStrata+s];
3239                   break;
3240                 }
3241               }
3242             }
3243           }
3244         }
3245         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3246       }
3247       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3248       /* Calculate stratumOffsets */
3249       newLabel->stratumOffsets[0] = 0;
3250       for (s = 0; s < newLabel->numStrata; ++s) {
3251         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3252       }
3253       /* Pack points and Scatter */
3254       if (!rank) {
3255         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3256         displs[0] = 0;
3257         for (p = 0; p < numProcs; ++p) {
3258           sendcnts[p] = 0;
3259           for (s = 0; s < next->numStrata; ++s) {
3260             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3261           }
3262           offsets[p]  = displs[p];
3263           displs[p+1] = displs[p] + sendcnts[p];
3264         }
3265         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3266         for (s = 0; s < next->numStrata; ++s) {
3267           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3268             const PetscInt point = next->points[p];
3269             PetscInt       proc;
3270 
3271             for (proc = 0; proc < numProcs; ++proc) {
3272               PetscInt dof, off, pPart;
3273 
3274               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3275               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3276               for (pPart = off; pPart < off+dof; ++pPart) {
3277                 if (partArray[pPart] == point) {
3278                   points[offsets[proc]++] = point;
3279                   break;
3280                 }
3281               }
3282             }
3283           }
3284         }
3285       }
3286       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3287       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3288       ierr = PetscFree(points);CHKERRQ(ierr);
3289       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3290       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3291       /* Renumber points */
3292       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3293       /* Sort points */
3294       for (s = 0; s < newLabel->numStrata; ++s) {
3295         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3296       }
3297       /* Insert into list */
3298       if (newNext) newNext->next = newLabel;
3299       else pmesh->labels = newLabel;
3300       newNext = newLabel;
3301       if (!rank) next = next->next;
3302     }
3303   }
3304   /* Cleanup Partition */
3305   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3306   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3307   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3308   ierr = ISDestroy(&part);CHKERRQ(ierr);
3309   /* Create point SF for parallel mesh */
3310   {
3311     const PetscInt *leaves;
3312     PetscSFNode    *remotePoints, *rowners, *lowners;
3313     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3314     PetscInt        pStart, pEnd;
3315 
3316     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3317     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3318     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3319     for (p=0; p<numRoots; p++) {
3320       rowners[p].rank  = -1;
3321       rowners[p].index = -1;
3322     }
3323     if (origCellPart) {
3324       /* Make sure cells in the original partition are not assigned to other procs */
3325       const PetscInt *origCells;
3326 
3327       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3328       for (p = 0; p < numProcs; ++p) {
3329         PetscInt dof, off, d;
3330 
3331         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3332         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3333         for (d = off; d < off+dof; ++d) {
3334           rowners[origCells[d]].rank = p;
3335         }
3336       }
3337       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3338     }
3339     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3340     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3341 
3342     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3343     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3344     for (p = 0; p < numLeaves; ++p) {
3345       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3346         lowners[p].rank  = rank;
3347         lowners[p].index = leaves ? leaves[p] : p;
3348       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3349         lowners[p].rank  = -2;
3350         lowners[p].index = -2;
3351       }
3352     }
3353     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3354       rowners[p].rank  = -3;
3355       rowners[p].index = -3;
3356     }
3357     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3358     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3359     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3360     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3361     for (p = 0; p < numLeaves; ++p) {
3362       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3363       if (lowners[p].rank != rank) ++numGhostPoints;
3364     }
3365     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3366     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3367     for (p = 0, gp = 0; p < numLeaves; ++p) {
3368       if (lowners[p].rank != rank) {
3369         ghostPoints[gp]        = leaves ? leaves[p] : p;
3370         remotePoints[gp].rank  = lowners[p].rank;
3371         remotePoints[gp].index = lowners[p].index;
3372         ++gp;
3373       }
3374     }
3375     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3376     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3377     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3378   }
3379   /* Cleanup */
3380   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3381   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3382   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3383   PetscFunctionReturn(0);
3384 }
3385 
3386 #undef __FUNCT__
3387 #define __FUNCT__ "DMPlexRenumber_Private"
3388 /*
3389   Reasons to renumber:
3390 
3391   1) Permute points, e.g. bandwidth reduction (Renumber)
3392 
3393     a) Must not mix strata
3394 
3395   2) Shift numbers for point insertion (Shift)
3396 
3397     a) Want operation brken into parts so that insertion can be interleaved
3398 
3399   renumbering - An IS which provides the new numbering
3400 */
3401 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3402 {
3403   PetscFunctionBegin;
3404   PetscFunctionReturn(0);
3405 }
3406 
3407 #undef __FUNCT__
3408 #define __FUNCT__ "DMPlexShiftPoint_Private"
3409 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3410 {
3411   if (depth < 0) return p;
3412   /* Cells    */ if (p < depthEnd[depth])   return p;
3413   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3414   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3415   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3416 }
3417 
3418 #undef __FUNCT__
3419 #define __FUNCT__ "DMPlexShiftSizes_Private"
3420 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3421 {
3422   PetscInt      *depthEnd;
3423   PetscInt       depth = 0, d, pStart, pEnd, p;
3424   PetscErrorCode ierr;
3425 
3426   PetscFunctionBegin;
3427   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3428   if (depth < 0) PetscFunctionReturn(0);
3429   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3430   /* Step 1: Expand chart */
3431   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3432   for (d = 0; d <= depth; ++d) {
3433     pEnd += depthShift[d];
3434     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3435   }
3436   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3437   /* Step 2: Set cone and support sizes */
3438   for (d = 0; d <= depth; ++d) {
3439     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3440     for (p = pStart; p < pEnd; ++p) {
3441       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3442       PetscInt size;
3443 
3444       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3445       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3446       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3447       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3448     }
3449   }
3450   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3451   PetscFunctionReturn(0);
3452 }
3453 
3454 #undef __FUNCT__
3455 #define __FUNCT__ "DMPlexShiftPoints_Private"
3456 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3457 {
3458   PetscInt      *depthEnd, *newpoints;
3459   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3460   PetscErrorCode ierr;
3461 
3462   PetscFunctionBegin;
3463   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3464   if (depth < 0) PetscFunctionReturn(0);
3465   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3466   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3467   for (d = 0; d <= depth; ++d) {
3468     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3469   }
3470   /* Step 5: Set cones and supports */
3471   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3472   for (p = pStart; p < pEnd; ++p) {
3473     const PetscInt *points = NULL, *orientations = NULL;
3474     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3475 
3476     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3477     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3478     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3479     for (i = 0; i < size; ++i) {
3480       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3481     }
3482     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3483     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3484     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3485     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3486     for (i = 0; i < size; ++i) {
3487       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3488     }
3489     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3490   }
3491   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3492   PetscFunctionReturn(0);
3493 }
3494 
3495 #undef __FUNCT__
3496 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3497 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3498 {
3499   PetscSection   coordSection, newCoordSection;
3500   Vec            coordinates, newCoordinates;
3501   PetscScalar   *coords, *newCoords;
3502   PetscInt      *depthEnd, coordSize;
3503   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3504   PetscErrorCode ierr;
3505 
3506   PetscFunctionBegin;
3507   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3508   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3509   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3510   for (d = 0; d <= depth; ++d) {
3511     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3512   }
3513   /* Step 8: Convert coordinates */
3514   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3515   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3516   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3517   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3518   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3519   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3520   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3521   for (v = vStartNew; v < vEndNew; ++v) {
3522     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3523     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3524   }
3525   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3526   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3527   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3528   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3529   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3530   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3531   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3532   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3533   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3534   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3535   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3536   for (v = vStart; v < vEnd; ++v) {
3537     PetscInt dof, off, noff, d;
3538 
3539     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3540     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3541     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3542     for (d = 0; d < dof; ++d) {
3543       newCoords[noff+d] = coords[off+d];
3544     }
3545   }
3546   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3547   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3548   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3549   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3550   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3551   PetscFunctionReturn(0);
3552 }
3553 
3554 #undef __FUNCT__
3555 #define __FUNCT__ "DMPlexShiftSF_Private"
3556 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3557 {
3558   PetscInt          *depthEnd;
3559   PetscInt           depth = 0, d;
3560   PetscSF            sfPoint, sfPointNew;
3561   const PetscSFNode *remotePoints;
3562   PetscSFNode       *gremotePoints;
3563   const PetscInt    *localPoints;
3564   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3565   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3566   PetscMPIInt        numProcs;
3567   PetscErrorCode     ierr;
3568 
3569   PetscFunctionBegin;
3570   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3571   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3572   for (d = 0; d <= depth; ++d) {
3573     totShift += depthShift[d];
3574     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3575   }
3576   /* Step 9: Convert pointSF */
3577   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3578   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3579   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3580   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3581   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3582   if (numRoots >= 0) {
3583     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3584     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3585     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3586     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3587     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3588     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3589     for (l = 0; l < numLeaves; ++l) {
3590       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3591       gremotePoints[l].rank  = remotePoints[l].rank;
3592       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3593     }
3594     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3595     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3596   }
3597   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3598   PetscFunctionReturn(0);
3599 }
3600 
3601 #undef __FUNCT__
3602 #define __FUNCT__ "DMPlexShiftLabels_Private"
3603 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3604 {
3605   PetscSF            sfPoint;
3606   DMLabel            vtkLabel, ghostLabel;
3607   PetscInt          *depthEnd;
3608   const PetscSFNode *leafRemote;
3609   const PetscInt    *leafLocal;
3610   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3611   PetscMPIInt        rank;
3612   PetscErrorCode     ierr;
3613 
3614   PetscFunctionBegin;
3615   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3616   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3617   for (d = 0; d <= depth; ++d) {
3618     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3619   }
3620   /* Step 10: Convert labels */
3621   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3622   for (l = 0; l < numLabels; ++l) {
3623     DMLabel         label, newlabel;
3624     const char     *lname;
3625     PetscBool       isDepth;
3626     IS              valueIS;
3627     const PetscInt *values;
3628     PetscInt        numValues, val;
3629 
3630     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3631     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3632     if (isDepth) continue;
3633     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3634     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3635     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3636     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3637     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3638     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3639     for (val = 0; val < numValues; ++val) {
3640       IS              pointIS;
3641       const PetscInt *points;
3642       PetscInt        numPoints, p;
3643 
3644       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3645       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3646       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3647       for (p = 0; p < numPoints; ++p) {
3648         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3649 
3650         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3651       }
3652       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3653       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3654     }
3655     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3656     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3657   }
3658   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3659   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3660   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3661   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3662   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3663   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3664   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3665   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3666   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3667   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3668   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3669     for (; c < leafLocal[l] && c < cEnd; ++c) {
3670       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3671     }
3672     if (leafLocal[l] >= cEnd) break;
3673     if (leafRemote[l].rank == rank) {
3674       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3675     } else {
3676       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3677     }
3678   }
3679   for (; c < cEnd; ++c) {
3680     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3681   }
3682   if (0) {
3683     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3684     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3685     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3686   }
3687   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3688   for (f = fStart; f < fEnd; ++f) {
3689     PetscInt numCells;
3690 
3691     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3692     if (numCells < 2) {
3693       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3694     } else {
3695       const PetscInt *cells = NULL;
3696       PetscInt        vA, vB;
3697 
3698       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3699       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3700       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3701       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3702     }
3703   }
3704   if (0) {
3705     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3706     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3707     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3708   }
3709   PetscFunctionReturn(0);
3710 }
3711 
3712 #undef __FUNCT__
3713 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3714 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3715 {
3716   DMLabel         label;
3717   IS              valueIS;
3718   const PetscInt *values;
3719   PetscInt       *depthShift;
3720   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3721   PetscErrorCode  ierr;
3722 
3723   PetscFunctionBegin;
3724   /* Count ghost cells */
3725   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3726   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3727   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3728   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3729 
3730   *numGhostCells = 0;
3731   for (fs = 0; fs < numFS; ++fs) {
3732     PetscInt numBdFaces;
3733 
3734     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3735 
3736     *numGhostCells += numBdFaces;
3737   }
3738   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3739   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3740   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3741   if (depth >= 0) depthShift[depth] = *numGhostCells;
3742   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3743   /* Step 3: Set cone/support sizes for new points */
3744   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3745   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3746     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3747   }
3748   for (fs = 0; fs < numFS; ++fs) {
3749     IS              faceIS;
3750     const PetscInt *faces;
3751     PetscInt        numFaces, f;
3752 
3753     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3754     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3755     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3756     for (f = 0; f < numFaces; ++f) {
3757       PetscInt size;
3758 
3759       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3760       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3761       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3762     }
3763     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3764     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3765   }
3766   /* Step 4: Setup ghosted DM */
3767   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3768   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3769   /* Step 6: Set cones and supports for new points */
3770   ghostCell = cEnd;
3771   for (fs = 0; fs < numFS; ++fs) {
3772     IS              faceIS;
3773     const PetscInt *faces;
3774     PetscInt        numFaces, f;
3775 
3776     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3777     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3778     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3779     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3780       PetscInt newFace = faces[f] + *numGhostCells;
3781 
3782       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3783       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3784     }
3785     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3786     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3787   }
3788   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3789   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3790   /* Step 7: Stratify */
3791   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3792   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3793   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3794   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3795   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3796   PetscFunctionReturn(0);
3797 }
3798 
3799 #undef __FUNCT__
3800 #define __FUNCT__ "DMPlexConstructGhostCells"
3801 /*@C
3802   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3803 
3804   Collective on dm
3805 
3806   Input Parameters:
3807 + dm - The original DM
3808 - labelName - The label specifying the boundary faces (this could be auto-generated)
3809 
3810   Output Parameters:
3811 + numGhostCells - The number of ghost cells added to the DM
3812 - dmGhosted - The new DM
3813 
3814   Level: developer
3815 
3816 .seealso: DMCreate()
3817 */
3818 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3819 {
3820   DM             gdm;
3821   PetscInt       dim;
3822   PetscErrorCode ierr;
3823 
3824   PetscFunctionBegin;
3825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3826   PetscValidPointer(numGhostCells, 3);
3827   PetscValidPointer(dmGhosted, 4);
3828   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3829   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3830   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3831   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3832   switch (dim) {
3833   case 2:
3834     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3835     break;
3836   default:
3837     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3838   }
3839   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3840   *dmGhosted = gdm;
3841   PetscFunctionReturn(0);
3842 }
3843 
3844 #undef __FUNCT__
3845 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3846 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3847 {
3848   MPI_Comm        comm;
3849   IS              valueIS, *pointIS;
3850   const PetscInt *values, **splitPoints;
3851   PetscSection    coordSection;
3852   Vec             coordinates;
3853   PetscScalar    *coords;
3854   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3855   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3856   PetscErrorCode  ierr;
3857 
3858   PetscFunctionBegin;
3859   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3860   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3861   /* Count split points and add cohesive cells */
3862   if (label) {
3863     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3864     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3865     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3866   }
3867   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3868   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3869   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3870   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3871   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3872   for (d = 0; d <= depth; ++d) {
3873     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3874     numSplitPoints[d] = 0;
3875     splitPoints[d]    = NULL;
3876     pointIS[d]        = NULL;
3877   }
3878   for (sp = 0; sp < numSP; ++sp) {
3879     const PetscInt dep = values[sp];
3880 
3881     if ((dep < 0) || (dep > depth)) continue;
3882     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3883     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3884     if (pointIS[dep]) {
3885       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3886       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3887     }
3888   }
3889   if (depth >= 0) {
3890     /* Calculate number of additional points */
3891     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3892     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3893     /* Calculate hybrid bound for each dimension */
3894     pMaxNew[0] += depthShift[depth];
3895     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3896     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3897 
3898     /* Calculate point offset for each dimension */
3899     depthOffset[depth] = 0;
3900     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3901     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3902     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3903   }
3904   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3905   /* Step 3: Set cone/support sizes for new points */
3906   for (dep = 0; dep <= depth; ++dep) {
3907     for (p = 0; p < numSplitPoints[dep]; ++p) {
3908       const PetscInt  oldp   = splitPoints[dep][p];
3909       const PetscInt  newp   = depthOffset[dep] + oldp;
3910       const PetscInt  splitp = pMaxNew[dep] + p;
3911       const PetscInt *support;
3912       PetscInt        coneSize, supportSize, q, e;
3913 
3914       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3915       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3916       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3917       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3918       if (dep == depth-1) {
3919         const PetscInt ccell = pMaxNew[depth] + p;
3920         /* Add cohesive cells, they are prisms */
3921         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3922       } else if (dep == 0) {
3923         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3924 
3925         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3926         /* Split old vertex: Edges in old split faces and new cohesive edge */
3927         for (e = 0, q = 0; e < supportSize; ++e) {
3928           PetscInt val;
3929 
3930           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3931           if ((val == 1) || (val == (shift + 1))) ++q;
3932         }
3933         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3934         /* Split new vertex: Edges in new split faces and new cohesive edge */
3935         for (e = 0, q = 0; e < supportSize; ++e) {
3936           PetscInt val;
3937 
3938           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3939           if ((val == 1) || (val == -(shift + 1))) ++q;
3940         }
3941         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3942         /* Add cohesive edges */
3943         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3944         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3945       } else if (dep == dim-2) {
3946         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3947         /* Split old edge: Faces in positive side cells and old split faces */
3948         for (e = 0, q = 0; e < supportSize; ++e) {
3949           PetscInt val;
3950 
3951           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3952           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
3953         }
3954         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
3955         /* Split new edge: Faces in negative side cells and new split faces */
3956         for (e = 0, q = 0; e < supportSize; ++e) {
3957           PetscInt val;
3958 
3959           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3960           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
3961         }
3962         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
3963       }
3964     }
3965   }
3966   /* Step 4: Setup split DM */
3967   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3968   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3969   /* Step 6: Set cones and supports for new points */
3970   for (dep = 0; dep <= depth; ++dep) {
3971     for (p = 0; p < numSplitPoints[dep]; ++p) {
3972       const PetscInt  oldp   = splitPoints[dep][p];
3973       const PetscInt  newp   = depthOffset[dep] + oldp;
3974       const PetscInt  splitp = pMaxNew[dep] + p;
3975       const PetscInt *cone, *support, *ornt;
3976       PetscInt        coneSize, supportSize, q, v, e, s;
3977 
3978       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3979       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
3980       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
3981       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3982       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3983       if (dep == depth-1) {
3984         const PetscInt  ccell = pMaxNew[depth] + p;
3985         const PetscInt *supportF;
3986 
3987         /* Split face:       copy in old face to new face to start */
3988         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
3989         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
3990         /* Split old face:   old vertices/edges in cone so no change */
3991         /* Split new face:   new vertices/edges in cone */
3992         for (q = 0; q < coneSize; ++q) {
3993           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
3994 
3995           coneNew[2+q] = pMaxNew[dim-2] + v;
3996         }
3997         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
3998         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
3999         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4000         coneNew[0] = newp;
4001         coneNew[1] = splitp;
4002         for (q = 0; q < coneSize; ++q) {
4003           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4004         }
4005         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4006 
4007 
4008         for (s = 0; s < supportSize; ++s) {
4009           PetscInt val;
4010 
4011           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4012           if (val < 0) {
4013             /* Split old face:   Replace negative side cell with cohesive cell */
4014             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4015           } else {
4016             /* Split new face:   Replace positive side cell with cohesive cell */
4017             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4018           }
4019         }
4020       } else if (dep == 0) {
4021         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4022 
4023         /* Split old vertex: Edges in old split faces and new cohesive edge */
4024         for (e = 0, q = 0; e < supportSize; ++e) {
4025           PetscInt val;
4026 
4027           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4028           if ((val == 1) || (val == (shift + 1))) {
4029             supportNew[q++] = depthOffset[1] + support[e];
4030           }
4031         }
4032         supportNew[q] = cedge;
4033 
4034         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4035         /* Split new vertex: Edges in new split faces and new cohesive edge */
4036         for (e = 0, q = 0; e < supportSize; ++e) {
4037           PetscInt val, edge;
4038 
4039           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4040           if (val == 1) {
4041             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4042             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4043             supportNew[q++] = pMaxNew[1] + edge;
4044           } else if (val == -(shift + 1)) {
4045             supportNew[q++] = depthOffset[1] + support[e];
4046           }
4047         }
4048         supportNew[q] = cedge;
4049         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4050         /* Cohesive edge:    Old and new split vertex, punting on support */
4051         coneNew[0] = newp;
4052         coneNew[1] = splitp;
4053         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4054       } else if (dep == dim-2) {
4055         /* Split old edge:   old vertices in cone so no change */
4056         /* Split new edge:   new vertices in cone */
4057         for (q = 0; q < coneSize; ++q) {
4058           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4059 
4060           coneNew[q] = pMaxNew[dim-3] + v;
4061         }
4062         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4063         /* Split old edge: Faces in positive side cells and old split faces */
4064         for (e = 0, q = 0; e < supportSize; ++e) {
4065           PetscInt val;
4066 
4067           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4068           if ((val == dim-1) || (val == (shift + dim-1))) {
4069             supportNew[q++] = depthOffset[dim-1] + support[e];
4070           }
4071         }
4072         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4073         /* Split new edge: Faces in negative side cells and new split faces */
4074         for (e = 0, q = 0; e < supportSize; ++e) {
4075           PetscInt val, face;
4076 
4077           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4078           if (val == dim-1) {
4079             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4080             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4081             supportNew[q++] = pMaxNew[dim-1] + face;
4082           } else if (val == -(shift + dim-1)) {
4083             supportNew[q++] = depthOffset[dim-1] + support[e];
4084           }
4085         }
4086         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4087       }
4088     }
4089   }
4090   /* Step 6b: Replace split points in negative side cones */
4091   for (sp = 0; sp < numSP; ++sp) {
4092     PetscInt        dep = values[sp];
4093     IS              pIS;
4094     PetscInt        numPoints;
4095     const PetscInt *points;
4096 
4097     if (dep >= 0) continue;
4098     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4099     if (!pIS) continue;
4100     dep  = -dep - shift;
4101     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4102     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4103     for (p = 0; p < numPoints; ++p) {
4104       const PetscInt  oldp = points[p];
4105       const PetscInt  newp = depthOffset[dep] + oldp;
4106       const PetscInt *cone;
4107       PetscInt        coneSize, c;
4108       PetscBool       replaced = PETSC_FALSE;
4109 
4110       /* Negative edge: replace split vertex */
4111       /* Negative cell: replace split face */
4112       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4113       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4114       for (c = 0; c < coneSize; ++c) {
4115         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4116         PetscInt       csplitp, cp, val;
4117 
4118         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4119         if (val == dep-1) {
4120           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4121           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4122           csplitp  = pMaxNew[dep-1] + cp;
4123           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4124           replaced = PETSC_TRUE;
4125         }
4126       }
4127       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4128     }
4129     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4130     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4131   }
4132   /* Step 7: Stratify */
4133   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4134   /* Step 8: Coordinates */
4135   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4136   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4137   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4138   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4139   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4140     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4141     const PetscInt splitp = pMaxNew[0] + v;
4142     PetscInt       dof, off, soff, d;
4143 
4144     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4145     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4146     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4147     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4148   }
4149   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4150   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4151   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4152   /* Step 10: Labels */
4153   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4154   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4155   for (dep = 0; dep <= depth; ++dep) {
4156     for (p = 0; p < numSplitPoints[dep]; ++p) {
4157       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4158       const PetscInt splitp = pMaxNew[dep] + p;
4159       PetscInt       l;
4160 
4161       for (l = 0; l < numLabels; ++l) {
4162         DMLabel     mlabel;
4163         const char *lname;
4164         PetscInt    val;
4165 
4166         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4167         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4168         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4169         if (val >= 0) {
4170           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4171           if (dep == 0) {
4172             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4173             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4174           }
4175         }
4176       }
4177     }
4178   }
4179   for (sp = 0; sp < numSP; ++sp) {
4180     const PetscInt dep = values[sp];
4181 
4182     if ((dep < 0) || (dep > depth)) continue;
4183     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4184     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4185   }
4186   if (label) {
4187     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4188     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4189   }
4190   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4191   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4192   PetscFunctionReturn(0);
4193 }
4194 
4195 #undef __FUNCT__
4196 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4197 /*@C
4198   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4199 
4200   Collective on dm
4201 
4202   Input Parameters:
4203 + dm - The original DM
4204 - labelName - The label specifying the boundary faces (this could be auto-generated)
4205 
4206   Output Parameters:
4207 - dmSplit - The new DM
4208 
4209   Level: developer
4210 
4211 .seealso: DMCreate()
4212 */
4213 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4214 {
4215   DM             sdm;
4216   PetscInt       dim;
4217   PetscErrorCode ierr;
4218 
4219   PetscFunctionBegin;
4220   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4221   PetscValidPointer(dmSplit, 4);
4222   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4223   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4224   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4225   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4226   switch (dim) {
4227   case 2:
4228   case 3:
4229     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4230     break;
4231   default:
4232     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4233   }
4234   *dmSplit = sdm;
4235   PetscFunctionReturn(0);
4236 }
4237 
4238 #undef __FUNCT__
4239 #define __FUNCT__ "DMLabelCohesiveComplete"
4240 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4241 {
4242   IS              dimIS;
4243   const PetscInt *points;
4244   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4245   PetscErrorCode  ierr;
4246 
4247   PetscFunctionBegin;
4248   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4249   /* Cell orientation for face gives the side of the fault */
4250   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4251   if (!dimIS) PetscFunctionReturn(0);
4252   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4253   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4254   for (p = 0; p < numPoints; ++p) {
4255     const PetscInt *support;
4256     PetscInt        supportSize, s;
4257 
4258     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4259     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4260     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4261     for (s = 0; s < supportSize; ++s) {
4262       const PetscInt *cone, *ornt;
4263       PetscInt        coneSize, c;
4264       PetscBool       pos = PETSC_TRUE;
4265 
4266       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4267       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4268       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4269       for (c = 0; c < coneSize; ++c) {
4270         if (cone[c] == points[p]) {
4271           if (ornt[c] >= 0) {
4272             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4273           } else {
4274             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4275             pos  = PETSC_FALSE;
4276           }
4277           break;
4278         }
4279       }
4280       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]);
4281       /* Put faces touching the fault in the label */
4282       for (c = 0; c < coneSize; ++c) {
4283         const PetscInt point = cone[c];
4284 
4285         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4286         if (val == -1) {
4287           PetscInt *closure = NULL;
4288           PetscInt  closureSize, cl;
4289 
4290           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4291           for (cl = 0; cl < closureSize*2; cl += 2) {
4292             const PetscInt clp = closure[cl];
4293 
4294             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4295             if ((val >= 0) && (val < dim-1)) {
4296               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4297               break;
4298             }
4299           }
4300           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4301         }
4302       }
4303     }
4304   }
4305   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4306   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4307   /* Search for other cells/faces/edges connected to the fault by a vertex */
4308   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4309   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4310   if (!dimIS) PetscFunctionReturn(0);
4311   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4312   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4313   for (p = 0; p < numPoints; ++p) {
4314     PetscInt *star = NULL;
4315     PetscInt  starSize, s;
4316     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4317 
4318     /* First mark cells connected to the fault */
4319     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4320     while (again) {
4321       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4322       again = 0;
4323       for (s = 0; s < starSize*2; s += 2) {
4324         const PetscInt  point = star[s];
4325         const PetscInt *cone;
4326         PetscInt        coneSize, c;
4327 
4328         if ((point < cStart) || (point >= cEnd)) continue;
4329         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4330         if (val != -1) continue;
4331         again = 2;
4332         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4333         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4334         for (c = 0; c < coneSize; ++c) {
4335           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4336           if (val != -1) {
4337             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);
4338             if (val > 0) {
4339               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4340             } else {
4341               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4342             }
4343             again = 1;
4344             break;
4345           }
4346         }
4347       }
4348     }
4349     /* Classify the rest by cell membership */
4350     for (s = 0; s < starSize*2; s += 2) {
4351       const PetscInt point = star[s];
4352 
4353       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4354       if (val == -1) {
4355         PetscInt  *sstar = NULL;
4356         PetscInt   sstarSize, ss;
4357         PetscBool  marked = PETSC_FALSE;
4358 
4359         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4360         for (ss = 0; ss < sstarSize*2; ss += 2) {
4361           const PetscInt spoint = sstar[ss];
4362 
4363           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4364           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4365           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4366           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4367           if (val > 0) {
4368             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4369           } else {
4370             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4371           }
4372           marked = PETSC_TRUE;
4373           break;
4374         }
4375         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4376         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4377       }
4378     }
4379     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4380   }
4381   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4382   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4383   PetscFunctionReturn(0);
4384 }
4385 
4386 #undef __FUNCT__
4387 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4388 /*
4389   This takes as input the common mesh generator output, a list of the vertices for each cell
4390 */
4391 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4392 {
4393   PetscInt      *cone, c, p;
4394   PetscErrorCode ierr;
4395 
4396   PetscFunctionBegin;
4397   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4398   for (c = 0; c < numCells; ++c) {
4399     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4400   }
4401   ierr = DMSetUp(dm);CHKERRQ(ierr);
4402   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4403   for (c = 0; c < numCells; ++c) {
4404     for (p = 0; p < numCorners; ++p) {
4405       cone[p] = cells[c*numCorners+p]+numCells;
4406     }
4407     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4408   }
4409   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4410   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4411   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4412   PetscFunctionReturn(0);
4413 }
4414 
4415 #undef __FUNCT__
4416 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4417 /*
4418   This takes as input the coordinates for each vertex
4419 */
4420 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4421 {
4422   PetscSection   coordSection;
4423   Vec            coordinates;
4424   PetscScalar   *coords;
4425   PetscInt       coordSize, v, d;
4426   PetscErrorCode ierr;
4427 
4428   PetscFunctionBegin;
4429   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4430   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4431   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4432   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4433   for (v = numCells; v < numCells+numVertices; ++v) {
4434     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4435     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4436   }
4437   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4438   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4439   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4440   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4441   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4442   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4443   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4444   for (v = 0; v < numVertices; ++v) {
4445     for (d = 0; d < spaceDim; ++d) {
4446       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4447     }
4448   }
4449   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4450   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4451   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4452   PetscFunctionReturn(0);
4453 }
4454 
4455 #undef __FUNCT__
4456 #define __FUNCT__ "DMPlexCreateFromCellList"
4457 /*
4458   This takes as input the common mesh generator output, a list of the vertices for each cell
4459 */
4460 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4461 {
4462   PetscErrorCode ierr;
4463 
4464   PetscFunctionBegin;
4465   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4466   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4467   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4468   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4469   if (interpolate) {
4470     DM idm;
4471 
4472     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
4473     ierr = DMDestroy(dm);CHKERRQ(ierr);
4474     *dm  = idm;
4475   }
4476   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4477   PetscFunctionReturn(0);
4478 }
4479 
4480 #undef __FUNCT__
4481 #define __FUNCT__ "DMPlexCreateFromDAG"
4482 /*
4483   This takes as input the raw Hasse Diagram data
4484 */
4485 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
4486 {
4487   Vec            coordinates;
4488   PetscSection   coordSection;
4489   PetscScalar    *coords;
4490   PetscInt       coordSize, firstVertex = numPoints[depth], pStart = 0, pEnd = 0, p, v, dim, d, off;
4491   PetscErrorCode ierr;
4492 
4493   PetscFunctionBegin;
4494   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4495   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
4496   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
4497   for (p = pStart; p < pEnd; ++p) {
4498     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
4499   }
4500   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
4501   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
4502     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
4503     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
4504   }
4505   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4506   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4507   /* Build coordinates */
4508   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4509   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4510   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
4511   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
4512   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
4513     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
4514   }
4515   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4516   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4517   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4518   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4519   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4520   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4521   for (v = 0; v < numPoints[0]; ++v) {
4522     PetscInt off;
4523 
4524     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
4525     for (d = 0; d < dim; ++d) {
4526       coords[off+d] = vertexCoords[v*dim+d];
4527     }
4528   }
4529   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4530   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4531   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4532   PetscFunctionReturn(0);
4533 }
4534 
4535 #if defined(PETSC_HAVE_TRIANGLE)
4536 #include <triangle.h>
4537 
4538 #undef __FUNCT__
4539 #define __FUNCT__ "InitInput_Triangle"
4540 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4541 {
4542   PetscFunctionBegin;
4543   inputCtx->numberofpoints             = 0;
4544   inputCtx->numberofpointattributes    = 0;
4545   inputCtx->pointlist                  = NULL;
4546   inputCtx->pointattributelist         = NULL;
4547   inputCtx->pointmarkerlist            = NULL;
4548   inputCtx->numberofsegments           = 0;
4549   inputCtx->segmentlist                = NULL;
4550   inputCtx->segmentmarkerlist          = NULL;
4551   inputCtx->numberoftriangleattributes = 0;
4552   inputCtx->trianglelist               = NULL;
4553   inputCtx->numberofholes              = 0;
4554   inputCtx->holelist                   = NULL;
4555   inputCtx->numberofregions            = 0;
4556   inputCtx->regionlist                 = NULL;
4557   PetscFunctionReturn(0);
4558 }
4559 
4560 #undef __FUNCT__
4561 #define __FUNCT__ "InitOutput_Triangle"
4562 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4563 {
4564   PetscFunctionBegin;
4565   outputCtx->numberofpoints        = 0;
4566   outputCtx->pointlist             = NULL;
4567   outputCtx->pointattributelist    = NULL;
4568   outputCtx->pointmarkerlist       = NULL;
4569   outputCtx->numberoftriangles     = 0;
4570   outputCtx->trianglelist          = NULL;
4571   outputCtx->triangleattributelist = NULL;
4572   outputCtx->neighborlist          = NULL;
4573   outputCtx->segmentlist           = NULL;
4574   outputCtx->segmentmarkerlist     = NULL;
4575   outputCtx->numberofedges         = 0;
4576   outputCtx->edgelist              = NULL;
4577   outputCtx->edgemarkerlist        = NULL;
4578   PetscFunctionReturn(0);
4579 }
4580 
4581 #undef __FUNCT__
4582 #define __FUNCT__ "FiniOutput_Triangle"
4583 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4584 {
4585   PetscFunctionBegin;
4586   free(outputCtx->pointmarkerlist);
4587   free(outputCtx->edgelist);
4588   free(outputCtx->edgemarkerlist);
4589   free(outputCtx->trianglelist);
4590   free(outputCtx->neighborlist);
4591   PetscFunctionReturn(0);
4592 }
4593 
4594 #undef __FUNCT__
4595 #define __FUNCT__ "DMPlexGenerate_Triangle"
4596 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4597 {
4598   MPI_Comm             comm;
4599   PetscInt             dim              = 2;
4600   const PetscBool      createConvexHull = PETSC_FALSE;
4601   const PetscBool      constrained      = PETSC_FALSE;
4602   struct triangulateio in;
4603   struct triangulateio out;
4604   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4605   PetscMPIInt          rank;
4606   PetscErrorCode       ierr;
4607 
4608   PetscFunctionBegin;
4609   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4610   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4611   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4612   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4613   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4614 
4615   in.numberofpoints = vEnd - vStart;
4616   if (in.numberofpoints > 0) {
4617     PetscSection coordSection;
4618     Vec          coordinates;
4619     PetscScalar *array;
4620 
4621     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4622     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4623     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4624     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4625     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4626     for (v = vStart; v < vEnd; ++v) {
4627       const PetscInt idx = v - vStart;
4628       PetscInt       off, d;
4629 
4630       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4631       for (d = 0; d < dim; ++d) {
4632         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4633       }
4634       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4635     }
4636     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4637   }
4638   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4639   in.numberofsegments = eEnd - eStart;
4640   if (in.numberofsegments > 0) {
4641     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4642     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4643     for (e = eStart; e < eEnd; ++e) {
4644       const PetscInt  idx = e - eStart;
4645       const PetscInt *cone;
4646 
4647       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4648 
4649       in.segmentlist[idx*2+0] = cone[0] - vStart;
4650       in.segmentlist[idx*2+1] = cone[1] - vStart;
4651 
4652       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4653     }
4654   }
4655 #if 0 /* Do not currently support holes */
4656   PetscReal *holeCoords;
4657   PetscInt   h, d;
4658 
4659   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4660   if (in.numberofholes > 0) {
4661     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4662     for (h = 0; h < in.numberofholes; ++h) {
4663       for (d = 0; d < dim; ++d) {
4664         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4665       }
4666     }
4667   }
4668 #endif
4669   if (!rank) {
4670     char args[32];
4671 
4672     /* Take away 'Q' for verbose output */
4673     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4674     if (createConvexHull) {
4675       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4676     }
4677     if (constrained) {
4678       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4679     }
4680     triangulate(args, &in, &out, NULL);
4681   }
4682   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4683   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4684   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4685   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4686   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4687 
4688   {
4689     const PetscInt numCorners  = 3;
4690     const PetscInt numCells    = out.numberoftriangles;
4691     const PetscInt numVertices = out.numberofpoints;
4692     const int     *cells      = out.trianglelist;
4693     const double  *meshCoords = out.pointlist;
4694 
4695     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4696     /* Set labels */
4697     for (v = 0; v < numVertices; ++v) {
4698       if (out.pointmarkerlist[v]) {
4699         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4700       }
4701     }
4702     if (interpolate) {
4703       for (e = 0; e < out.numberofedges; e++) {
4704         if (out.edgemarkerlist[e]) {
4705           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4706           const PetscInt *edges;
4707           PetscInt        numEdges;
4708 
4709           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4710           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4711           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4712           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4713         }
4714       }
4715     }
4716     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4717   }
4718 #if 0 /* Do not currently support holes */
4719   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4720 #endif
4721   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4722   PetscFunctionReturn(0);
4723 }
4724 
4725 #undef __FUNCT__
4726 #define __FUNCT__ "DMPlexRefine_Triangle"
4727 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4728 {
4729   MPI_Comm             comm;
4730   PetscInt             dim  = 2;
4731   struct triangulateio in;
4732   struct triangulateio out;
4733   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4734   PetscMPIInt          rank;
4735   PetscErrorCode       ierr;
4736 
4737   PetscFunctionBegin;
4738   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4739   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4740   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4741   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4742   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4743   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4744   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4745 
4746   in.numberofpoints = vEnd - vStart;
4747   if (in.numberofpoints > 0) {
4748     PetscSection coordSection;
4749     Vec          coordinates;
4750     PetscScalar *array;
4751 
4752     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4753     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4754     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4755     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4756     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4757     for (v = vStart; v < vEnd; ++v) {
4758       const PetscInt idx = v - vStart;
4759       PetscInt       off, d;
4760 
4761       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4762       for (d = 0; d < dim; ++d) {
4763         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4764       }
4765       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4766     }
4767     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4768   }
4769   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4770 
4771   in.numberofcorners   = 3;
4772   in.numberoftriangles = cEnd - cStart;
4773 
4774   in.trianglearealist  = (double*) maxVolumes;
4775   if (in.numberoftriangles > 0) {
4776     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4777     for (c = cStart; c < cEnd; ++c) {
4778       const PetscInt idx      = c - cStart;
4779       PetscInt      *closure = NULL;
4780       PetscInt       closureSize;
4781 
4782       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4783       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4784       for (v = 0; v < 3; ++v) {
4785         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4786       }
4787       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4788     }
4789   }
4790   /* TODO: Segment markers are missing on input */
4791 #if 0 /* Do not currently support holes */
4792   PetscReal *holeCoords;
4793   PetscInt   h, d;
4794 
4795   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4796   if (in.numberofholes > 0) {
4797     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4798     for (h = 0; h < in.numberofholes; ++h) {
4799       for (d = 0; d < dim; ++d) {
4800         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4801       }
4802     }
4803   }
4804 #endif
4805   if (!rank) {
4806     char args[32];
4807 
4808     /* Take away 'Q' for verbose output */
4809     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4810     triangulate(args, &in, &out, NULL);
4811   }
4812   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4813   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4814   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4815   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4816   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4817 
4818   {
4819     const PetscInt numCorners  = 3;
4820     const PetscInt numCells    = out.numberoftriangles;
4821     const PetscInt numVertices = out.numberofpoints;
4822     const int     *cells      = out.trianglelist;
4823     const double  *meshCoords = out.pointlist;
4824     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4825 
4826     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4827     /* Set labels */
4828     for (v = 0; v < numVertices; ++v) {
4829       if (out.pointmarkerlist[v]) {
4830         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4831       }
4832     }
4833     if (interpolate) {
4834       PetscInt e;
4835 
4836       for (e = 0; e < out.numberofedges; e++) {
4837         if (out.edgemarkerlist[e]) {
4838           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4839           const PetscInt *edges;
4840           PetscInt        numEdges;
4841 
4842           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4843           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4844           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4845           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4846         }
4847       }
4848     }
4849     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4850   }
4851 #if 0 /* Do not currently support holes */
4852   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4853 #endif
4854   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4855   PetscFunctionReturn(0);
4856 }
4857 #endif
4858 
4859 #if defined(PETSC_HAVE_TETGEN)
4860 #include <tetgen.h>
4861 #undef __FUNCT__
4862 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4863 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4864 {
4865   MPI_Comm       comm;
4866   const PetscInt dim  = 3;
4867   ::tetgenio     in;
4868   ::tetgenio     out;
4869   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4870   PetscMPIInt    rank;
4871   PetscErrorCode ierr;
4872 
4873   PetscFunctionBegin;
4874   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4875   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4876   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4877   in.numberofpoints = vEnd - vStart;
4878   if (in.numberofpoints > 0) {
4879     PetscSection coordSection;
4880     Vec          coordinates;
4881     PetscScalar *array;
4882 
4883     in.pointlist       = new double[in.numberofpoints*dim];
4884     in.pointmarkerlist = new int[in.numberofpoints];
4885 
4886     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4887     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4888     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4889     for (v = vStart; v < vEnd; ++v) {
4890       const PetscInt idx = v - vStart;
4891       PetscInt       off, d;
4892 
4893       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4894       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4895       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4896     }
4897     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4898   }
4899   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4900 
4901   in.numberoffacets = fEnd - fStart;
4902   if (in.numberoffacets > 0) {
4903     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4904     in.facetmarkerlist = new int[in.numberoffacets];
4905     for (f = fStart; f < fEnd; ++f) {
4906       const PetscInt idx     = f - fStart;
4907       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4908 
4909       in.facetlist[idx].numberofpolygons = 1;
4910       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4911       in.facetlist[idx].numberofholes    = 0;
4912       in.facetlist[idx].holelist         = NULL;
4913 
4914       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4915       for (p = 0; p < numPoints*2; p += 2) {
4916         const PetscInt point = points[p];
4917         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4918       }
4919 
4920       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4921       poly->numberofvertices = numVertices;
4922       poly->vertexlist       = new int[poly->numberofvertices];
4923       for (v = 0; v < numVertices; ++v) {
4924         const PetscInt vIdx = points[v] - vStart;
4925         poly->vertexlist[v] = vIdx;
4926       }
4927       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4928       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4929     }
4930   }
4931   if (!rank) {
4932     char args[32];
4933 
4934     /* Take away 'Q' for verbose output */
4935     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4936     ::tetrahedralize(args, &in, &out);
4937   }
4938   {
4939     const PetscInt numCorners  = 4;
4940     const PetscInt numCells    = out.numberoftetrahedra;
4941     const PetscInt numVertices = out.numberofpoints;
4942     const int     *cells      = out.tetrahedronlist;
4943     const double  *meshCoords = out.pointlist;
4944 
4945     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4946     /* Set labels */
4947     for (v = 0; v < numVertices; ++v) {
4948       if (out.pointmarkerlist[v]) {
4949         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4950       }
4951     }
4952     if (interpolate) {
4953       PetscInt e;
4954 
4955       for (e = 0; e < out.numberofedges; e++) {
4956         if (out.edgemarkerlist[e]) {
4957           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4958           const PetscInt *edges;
4959           PetscInt        numEdges;
4960 
4961           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4962           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4963           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4964           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4965         }
4966       }
4967       for (f = 0; f < out.numberoftrifaces; f++) {
4968         if (out.trifacemarkerlist[f]) {
4969           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4970           const PetscInt *faces;
4971           PetscInt        numFaces;
4972 
4973           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4974           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4975           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4976           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4977         }
4978       }
4979     }
4980     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4981   }
4982   PetscFunctionReturn(0);
4983 }
4984 
4985 #undef __FUNCT__
4986 #define __FUNCT__ "DMPlexRefine_Tetgen"
4987 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4988 {
4989   MPI_Comm       comm;
4990   const PetscInt dim  = 3;
4991   ::tetgenio     in;
4992   ::tetgenio     out;
4993   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4994   PetscMPIInt    rank;
4995   PetscErrorCode ierr;
4996 
4997   PetscFunctionBegin;
4998   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4999   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5000   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5001   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5002   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5003 
5004   in.numberofpoints = vEnd - vStart;
5005   if (in.numberofpoints > 0) {
5006     PetscSection coordSection;
5007     Vec          coordinates;
5008     PetscScalar *array;
5009 
5010     in.pointlist       = new double[in.numberofpoints*dim];
5011     in.pointmarkerlist = new int[in.numberofpoints];
5012 
5013     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5014     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5015     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5016     for (v = vStart; v < vEnd; ++v) {
5017       const PetscInt idx = v - vStart;
5018       PetscInt       off, d;
5019 
5020       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5021       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5022       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5023     }
5024     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5025   }
5026   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5027 
5028   in.numberofcorners       = 4;
5029   in.numberoftetrahedra    = cEnd - cStart;
5030   in.tetrahedronvolumelist = (double*) maxVolumes;
5031   if (in.numberoftetrahedra > 0) {
5032     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5033     for (c = cStart; c < cEnd; ++c) {
5034       const PetscInt idx      = c - cStart;
5035       PetscInt      *closure = NULL;
5036       PetscInt       closureSize;
5037 
5038       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5039       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5040       for (v = 0; v < 4; ++v) {
5041         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5042       }
5043       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5044     }
5045   }
5046   /* TODO: Put in boundary faces with markers */
5047   if (!rank) {
5048     char args[32];
5049 
5050     /* Take away 'Q' for verbose output */
5051     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5052     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5053     ::tetrahedralize(args, &in, &out);
5054   }
5055   in.tetrahedronvolumelist = NULL;
5056 
5057   {
5058     const PetscInt numCorners  = 4;
5059     const PetscInt numCells    = out.numberoftetrahedra;
5060     const PetscInt numVertices = out.numberofpoints;
5061     const int     *cells      = out.tetrahedronlist;
5062     const double  *meshCoords = out.pointlist;
5063     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5064 
5065     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5066     /* Set labels */
5067     for (v = 0; v < numVertices; ++v) {
5068       if (out.pointmarkerlist[v]) {
5069         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5070       }
5071     }
5072     if (interpolate) {
5073       PetscInt e, f;
5074 
5075       for (e = 0; e < out.numberofedges; e++) {
5076         if (out.edgemarkerlist[e]) {
5077           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5078           const PetscInt *edges;
5079           PetscInt        numEdges;
5080 
5081           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5082           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5083           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5084           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5085         }
5086       }
5087       for (f = 0; f < out.numberoftrifaces; f++) {
5088         if (out.trifacemarkerlist[f]) {
5089           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5090           const PetscInt *faces;
5091           PetscInt        numFaces;
5092 
5093           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5094           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5095           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5096           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5097         }
5098       }
5099     }
5100     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5101   }
5102   PetscFunctionReturn(0);
5103 }
5104 #endif
5105 
5106 #if defined(PETSC_HAVE_CTETGEN)
5107 #include "ctetgen.h"
5108 
5109 #undef __FUNCT__
5110 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5111 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5112 {
5113   MPI_Comm       comm;
5114   const PetscInt dim  = 3;
5115   PLC           *in, *out;
5116   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5117   PetscMPIInt    rank;
5118   PetscErrorCode ierr;
5119 
5120   PetscFunctionBegin;
5121   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5122   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5123   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5124   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5125   ierr = PLCCreate(&in);CHKERRQ(ierr);
5126   ierr = PLCCreate(&out);CHKERRQ(ierr);
5127 
5128   in->numberofpoints = vEnd - vStart;
5129   if (in->numberofpoints > 0) {
5130     PetscSection coordSection;
5131     Vec          coordinates;
5132     PetscScalar *array;
5133 
5134     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5135     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5136     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5137     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5138     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5139     for (v = vStart; v < vEnd; ++v) {
5140       const PetscInt idx = v - vStart;
5141       PetscInt       off, d, m;
5142 
5143       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5144       for (d = 0; d < dim; ++d) {
5145         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5146       }
5147       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5148 
5149       in->pointmarkerlist[idx] = (int) m;
5150     }
5151     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5152   }
5153   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5154 
5155   in->numberoffacets = fEnd - fStart;
5156   if (in->numberoffacets > 0) {
5157     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5158     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5159     for (f = fStart; f < fEnd; ++f) {
5160       const PetscInt idx     = f - fStart;
5161       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5162       polygon       *poly;
5163 
5164       in->facetlist[idx].numberofpolygons = 1;
5165 
5166       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5167 
5168       in->facetlist[idx].numberofholes    = 0;
5169       in->facetlist[idx].holelist         = NULL;
5170 
5171       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5172       for (p = 0; p < numPoints*2; p += 2) {
5173         const PetscInt point = points[p];
5174         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5175       }
5176 
5177       poly                   = in->facetlist[idx].polygonlist;
5178       poly->numberofvertices = numVertices;
5179       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5180       for (v = 0; v < numVertices; ++v) {
5181         const PetscInt vIdx = points[v] - vStart;
5182         poly->vertexlist[v] = vIdx;
5183       }
5184       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5185       in->facetmarkerlist[idx] = (int) m;
5186       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5187     }
5188   }
5189   if (!rank) {
5190     TetGenOpts t;
5191 
5192     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5193     t.in        = boundary; /* Should go away */
5194     t.plc       = 1;
5195     t.quality   = 1;
5196     t.edgesout  = 1;
5197     t.zeroindex = 1;
5198     t.quiet     = 1;
5199     t.verbose   = verbose;
5200     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5201     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5202   }
5203   {
5204     const PetscInt numCorners  = 4;
5205     const PetscInt numCells    = out->numberoftetrahedra;
5206     const PetscInt numVertices = out->numberofpoints;
5207     const int     *cells      = out->tetrahedronlist;
5208     const double  *meshCoords = out->pointlist;
5209 
5210     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5211     /* Set labels */
5212     for (v = 0; v < numVertices; ++v) {
5213       if (out->pointmarkerlist[v]) {
5214         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5215       }
5216     }
5217     if (interpolate) {
5218       PetscInt e;
5219 
5220       for (e = 0; e < out->numberofedges; e++) {
5221         if (out->edgemarkerlist[e]) {
5222           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5223           const PetscInt *edges;
5224           PetscInt        numEdges;
5225 
5226           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5227           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5228           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5229           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5230         }
5231       }
5232       for (f = 0; f < out->numberoftrifaces; f++) {
5233         if (out->trifacemarkerlist[f]) {
5234           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5235           const PetscInt *faces;
5236           PetscInt        numFaces;
5237 
5238           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5239           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5240           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5241           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5242         }
5243       }
5244     }
5245     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5246   }
5247 
5248   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5249   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5250   PetscFunctionReturn(0);
5251 }
5252 
5253 #undef __FUNCT__
5254 #define __FUNCT__ "DMPlexRefine_CTetgen"
5255 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5256 {
5257   MPI_Comm       comm;
5258   const PetscInt dim  = 3;
5259   PLC           *in, *out;
5260   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5261   PetscMPIInt    rank;
5262   PetscErrorCode ierr;
5263 
5264   PetscFunctionBegin;
5265   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5266   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5267   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5268   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5269   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5270   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5271   ierr = PLCCreate(&in);CHKERRQ(ierr);
5272   ierr = PLCCreate(&out);CHKERRQ(ierr);
5273 
5274   in->numberofpoints = vEnd - vStart;
5275   if (in->numberofpoints > 0) {
5276     PetscSection coordSection;
5277     Vec          coordinates;
5278     PetscScalar *array;
5279 
5280     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5281     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5282     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5283     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5284     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5285     for (v = vStart; v < vEnd; ++v) {
5286       const PetscInt idx = v - vStart;
5287       PetscInt       off, d, m;
5288 
5289       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5290       for (d = 0; d < dim; ++d) {
5291         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5292       }
5293       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5294 
5295       in->pointmarkerlist[idx] = (int) m;
5296     }
5297     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5298   }
5299   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5300 
5301   in->numberofcorners       = 4;
5302   in->numberoftetrahedra    = cEnd - cStart;
5303   in->tetrahedronvolumelist = maxVolumes;
5304   if (in->numberoftetrahedra > 0) {
5305     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5306     for (c = cStart; c < cEnd; ++c) {
5307       const PetscInt idx      = c - cStart;
5308       PetscInt      *closure = NULL;
5309       PetscInt       closureSize;
5310 
5311       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5312       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5313       for (v = 0; v < 4; ++v) {
5314         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5315       }
5316       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5317     }
5318   }
5319   if (!rank) {
5320     TetGenOpts t;
5321 
5322     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5323 
5324     t.in        = dm; /* Should go away */
5325     t.refine    = 1;
5326     t.varvolume = 1;
5327     t.quality   = 1;
5328     t.edgesout  = 1;
5329     t.zeroindex = 1;
5330     t.quiet     = 1;
5331     t.verbose   = verbose; /* Change this */
5332 
5333     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5334     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5335   }
5336   {
5337     const PetscInt numCorners  = 4;
5338     const PetscInt numCells    = out->numberoftetrahedra;
5339     const PetscInt numVertices = out->numberofpoints;
5340     const int     *cells       = out->tetrahedronlist;
5341     const double  *meshCoords  = out->pointlist;
5342     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5343 
5344     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5345     /* Set labels */
5346     for (v = 0; v < numVertices; ++v) {
5347       if (out->pointmarkerlist[v]) {
5348         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5349       }
5350     }
5351     if (interpolate) {
5352       PetscInt e, f;
5353 
5354       for (e = 0; e < out->numberofedges; e++) {
5355         if (out->edgemarkerlist[e]) {
5356           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5357           const PetscInt *edges;
5358           PetscInt        numEdges;
5359 
5360           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5361           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5362           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5363           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5364         }
5365       }
5366       for (f = 0; f < out->numberoftrifaces; f++) {
5367         if (out->trifacemarkerlist[f]) {
5368           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5369           const PetscInt *faces;
5370           PetscInt        numFaces;
5371 
5372           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5373           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5374           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5375           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5376         }
5377       }
5378     }
5379     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5380   }
5381   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5382   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5383   PetscFunctionReturn(0);
5384 }
5385 #endif
5386 
5387 #undef __FUNCT__
5388 #define __FUNCT__ "DMPlexGenerate"
5389 /*@C
5390   DMPlexGenerate - Generates a mesh.
5391 
5392   Not Collective
5393 
5394   Input Parameters:
5395 + boundary - The DMPlex boundary object
5396 . name - The mesh generation package name
5397 - interpolate - Flag to create intermediate mesh elements
5398 
5399   Output Parameter:
5400 . mesh - The DMPlex object
5401 
5402   Level: intermediate
5403 
5404 .keywords: mesh, elements
5405 .seealso: DMPlexCreate(), DMRefine()
5406 @*/
5407 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5408 {
5409   PetscInt       dim;
5410   char           genname[1024];
5411   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5412   PetscErrorCode ierr;
5413 
5414   PetscFunctionBegin;
5415   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5416   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5417   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5418   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5419   if (flg) name = genname;
5420   if (name) {
5421     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5422     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5423     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5424   }
5425   switch (dim) {
5426   case 1:
5427     if (!name || isTriangle) {
5428 #if defined(PETSC_HAVE_TRIANGLE)
5429       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5430 #else
5431       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5432 #endif
5433     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5434     break;
5435   case 2:
5436     if (!name || isCTetgen) {
5437 #if defined(PETSC_HAVE_CTETGEN)
5438       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5439 #else
5440       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5441 #endif
5442     } else if (isTetgen) {
5443 #if defined(PETSC_HAVE_TETGEN)
5444       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5445 #else
5446       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5447 #endif
5448     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5449     break;
5450   default:
5451     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5452   }
5453   PetscFunctionReturn(0);
5454 }
5455 
5456 typedef PetscInt CellRefiner;
5457 
5458 #undef __FUNCT__
5459 #define __FUNCT__ "GetDepthStart_Private"
5460 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5461 {
5462   PetscFunctionBegin;
5463   if (cStart) *cStart = 0;
5464   if (vStart) *vStart = depthSize[depth];
5465   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5466   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5467   PetscFunctionReturn(0);
5468 }
5469 
5470 #undef __FUNCT__
5471 #define __FUNCT__ "GetDepthEnd_Private"
5472 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5473 {
5474   PetscFunctionBegin;
5475   if (cEnd) *cEnd = depthSize[depth];
5476   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5477   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5478   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5479   PetscFunctionReturn(0);
5480 }
5481 
5482 #undef __FUNCT__
5483 #define __FUNCT__ "CellRefinerGetSizes"
5484 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5485 {
5486   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5487   PetscErrorCode ierr;
5488 
5489   PetscFunctionBegin;
5490   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5491   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5492   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5493   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5494   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5495   switch (refiner) {
5496   case 1:
5497     /* Simplicial 2D */
5498     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5499     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5500     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5501     break;
5502   case 3:
5503     /* Hybrid 2D */
5504     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5505     cMax = PetscMin(cEnd, cMax);
5506     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5507     fMax         = PetscMin(fEnd, fMax);
5508     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5509     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 */
5510     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5511     break;
5512   case 2:
5513     /* Hex 2D */
5514     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5515     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5516     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5517     break;
5518   default:
5519     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5520   }
5521   PetscFunctionReturn(0);
5522 }
5523 
5524 #undef __FUNCT__
5525 #define __FUNCT__ "CellRefinerSetConeSizes"
5526 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5527 {
5528   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5529   PetscErrorCode ierr;
5530 
5531   PetscFunctionBegin;
5532   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5533   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5534   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5535   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5536   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5537   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5538   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5539   switch (refiner) {
5540   case 1:
5541     /* Simplicial 2D */
5542     /* All cells have 3 faces */
5543     for (c = cStart; c < cEnd; ++c) {
5544       for (r = 0; r < 4; ++r) {
5545         const PetscInt newp = (c - cStart)*4 + r;
5546 
5547         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5548       }
5549     }
5550     /* Split faces have 2 vertices and the same cells as the parent */
5551     for (f = fStart; f < fEnd; ++f) {
5552       for (r = 0; r < 2; ++r) {
5553         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5554         PetscInt       size;
5555 
5556         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5557         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5558         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5559       }
5560     }
5561     /* Interior faces have 2 vertices and 2 cells */
5562     for (c = cStart; c < cEnd; ++c) {
5563       for (r = 0; r < 3; ++r) {
5564         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5565 
5566         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5567         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5568       }
5569     }
5570     /* Old vertices have identical supports */
5571     for (v = vStart; v < vEnd; ++v) {
5572       const PetscInt newp = vStartNew + (v - vStart);
5573       PetscInt       size;
5574 
5575       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5576       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5577     }
5578     /* Face vertices have 2 + cells*2 supports */
5579     for (f = fStart; f < fEnd; ++f) {
5580       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5581       PetscInt       size;
5582 
5583       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5584       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5585     }
5586     break;
5587   case 2:
5588     /* Hex 2D */
5589     /* All cells have 4 faces */
5590     for (c = cStart; c < cEnd; ++c) {
5591       for (r = 0; r < 4; ++r) {
5592         const PetscInt newp = (c - cStart)*4 + r;
5593 
5594         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5595       }
5596     }
5597     /* Split faces have 2 vertices and the same cells as the parent */
5598     for (f = fStart; f < fEnd; ++f) {
5599       for (r = 0; r < 2; ++r) {
5600         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5601         PetscInt       size;
5602 
5603         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5604         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5605         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5606       }
5607     }
5608     /* Interior faces have 2 vertices and 2 cells */
5609     for (c = cStart; c < cEnd; ++c) {
5610       for (r = 0; r < 4; ++r) {
5611         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5612 
5613         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5614         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5615       }
5616     }
5617     /* Old vertices have identical supports */
5618     for (v = vStart; v < vEnd; ++v) {
5619       const PetscInt newp = vStartNew + (v - vStart);
5620       PetscInt       size;
5621 
5622       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5623       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5624     }
5625     /* Face vertices have 2 + cells supports */
5626     for (f = fStart; f < fEnd; ++f) {
5627       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5628       PetscInt       size;
5629 
5630       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5631       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5632     }
5633     /* Cell vertices have 4 supports */
5634     for (c = cStart; c < cEnd; ++c) {
5635       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5636 
5637       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5638     }
5639     break;
5640   case 3:
5641     /* Hybrid 2D */
5642     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5643     cMax = PetscMin(cEnd, cMax);
5644     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5645     fMax = PetscMin(fEnd, fMax);
5646     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5647     /* Interior cells have 3 faces */
5648     for (c = cStart; c < cMax; ++c) {
5649       for (r = 0; r < 4; ++r) {
5650         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5651 
5652         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5653       }
5654     }
5655     /* Hybrid cells have 4 faces */
5656     for (c = cMax; c < cEnd; ++c) {
5657       for (r = 0; r < 2; ++r) {
5658         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5659 
5660         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5661       }
5662     }
5663     /* Interior split faces have 2 vertices and the same cells as the parent */
5664     for (f = fStart; f < fMax; ++f) {
5665       for (r = 0; r < 2; ++r) {
5666         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5667         PetscInt       size;
5668 
5669         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5670         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5671         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5672       }
5673     }
5674     /* Interior cell faces have 2 vertices and 2 cells */
5675     for (c = cStart; c < cMax; ++c) {
5676       for (r = 0; r < 3; ++r) {
5677         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5678 
5679         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5680         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5681       }
5682     }
5683     /* Hybrid faces have 2 vertices and the same cells */
5684     for (f = fMax; f < fEnd; ++f) {
5685       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5686       PetscInt       size;
5687 
5688       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5689       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5690       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5691     }
5692     /* Hybrid cell faces have 2 vertices and 2 cells */
5693     for (c = cMax; c < cEnd; ++c) {
5694       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5695 
5696       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5697       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5698     }
5699     /* Old vertices have identical supports */
5700     for (v = vStart; v < vEnd; ++v) {
5701       const PetscInt newp = vStartNew + (v - vStart);
5702       PetscInt       size;
5703 
5704       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5705       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5706     }
5707     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5708     for (f = fStart; f < fMax; ++f) {
5709       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5710       const PetscInt *support;
5711       PetscInt       size, newSize = 2, s;
5712 
5713       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5714       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5715       for (s = 0; s < size; ++s) {
5716         if (support[s] >= cMax) newSize += 1;
5717         else newSize += 2;
5718       }
5719       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5720     }
5721     break;
5722   default:
5723     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5724   }
5725   PetscFunctionReturn(0);
5726 }
5727 
5728 #undef __FUNCT__
5729 #define __FUNCT__ "CellRefinerSetCones"
5730 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5731 {
5732   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;
5733   PetscInt       maxSupportSize, *supportRef;
5734   PetscErrorCode ierr;
5735 
5736   PetscFunctionBegin;
5737   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5738   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5739   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5740   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5741   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5742   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5743   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5744   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5745   switch (refiner) {
5746   case 1:
5747     /* Simplicial 2D */
5748     /*
5749      2
5750      |\
5751      | \
5752      |  \
5753      |   \
5754      | C  \
5755      |     \
5756      |      \
5757      2---1---1
5758      |\  D  / \
5759      | 2   0   \
5760      |A \ /  B  \
5761      0---0-------1
5762      */
5763     /* All cells have 3 faces */
5764     for (c = cStart; c < cEnd; ++c) {
5765       const PetscInt  newp = cStartNew + (c - cStart)*4;
5766       const PetscInt *cone, *ornt;
5767       PetscInt        coneNew[3], orntNew[3];
5768 
5769       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5770       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5771       /* A triangle */
5772       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5773       orntNew[0] = ornt[0];
5774       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5775       orntNew[1] = -2;
5776       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5777       orntNew[2] = ornt[2];
5778       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5779       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5780 #if 1
5781       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);
5782       for (p = 0; p < 3; ++p) {
5783         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);
5784       }
5785 #endif
5786       /* B triangle */
5787       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5788       orntNew[0] = ornt[0];
5789       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5790       orntNew[1] = ornt[1];
5791       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5792       orntNew[2] = -2;
5793       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5794       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5795 #if 1
5796       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);
5797       for (p = 0; p < 3; ++p) {
5798         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);
5799       }
5800 #endif
5801       /* C triangle */
5802       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5803       orntNew[0] = -2;
5804       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5805       orntNew[1] = ornt[1];
5806       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5807       orntNew[2] = ornt[2];
5808       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5809       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5810 #if 1
5811       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);
5812       for (p = 0; p < 3; ++p) {
5813         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);
5814       }
5815 #endif
5816       /* D triangle */
5817       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5818       orntNew[0] = 0;
5819       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5820       orntNew[1] = 0;
5821       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5822       orntNew[2] = 0;
5823       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5824       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5825 #if 1
5826       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);
5827       for (p = 0; p < 3; ++p) {
5828         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);
5829       }
5830 #endif
5831     }
5832     /* Split faces have 2 vertices and the same cells as the parent */
5833     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5834     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5835     for (f = fStart; f < fEnd; ++f) {
5836       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5837 
5838       for (r = 0; r < 2; ++r) {
5839         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5840         const PetscInt *cone, *support;
5841         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5842 
5843         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5844         coneNew[0]       = vStartNew + (cone[0] - vStart);
5845         coneNew[1]       = vStartNew + (cone[1] - vStart);
5846         coneNew[(r+1)%2] = newv;
5847         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5848 #if 1
5849         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5850         for (p = 0; p < 2; ++p) {
5851           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);
5852         }
5853 #endif
5854         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5855         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5856         for (s = 0; s < supportSize; ++s) {
5857           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5858           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5859           for (c = 0; c < coneSize; ++c) {
5860             if (cone[c] == f) break;
5861           }
5862           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5863         }
5864         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5865 #if 1
5866         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5867         for (p = 0; p < supportSize; ++p) {
5868           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);
5869         }
5870 #endif
5871       }
5872     }
5873     /* Interior faces have 2 vertices and 2 cells */
5874     for (c = cStart; c < cEnd; ++c) {
5875       const PetscInt *cone;
5876 
5877       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5878       for (r = 0; r < 3; ++r) {
5879         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5880         PetscInt       coneNew[2];
5881         PetscInt       supportNew[2];
5882 
5883         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5884         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5885         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5886 #if 1
5887         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5888         for (p = 0; p < 2; ++p) {
5889           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);
5890         }
5891 #endif
5892         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5893         supportNew[1] = (c - cStart)*4 + 3;
5894         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5895 #if 1
5896         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5897         for (p = 0; p < 2; ++p) {
5898           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);
5899         }
5900 #endif
5901       }
5902     }
5903     /* Old vertices have identical supports */
5904     for (v = vStart; v < vEnd; ++v) {
5905       const PetscInt  newp = vStartNew + (v - vStart);
5906       const PetscInt *support, *cone;
5907       PetscInt        size, s;
5908 
5909       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5910       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5911       for (s = 0; s < size; ++s) {
5912         PetscInt r = 0;
5913 
5914         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5915         if (cone[1] == v) r = 1;
5916         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5917       }
5918       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5919 #if 1
5920       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5921       for (p = 0; p < size; ++p) {
5922         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);
5923       }
5924 #endif
5925     }
5926     /* Face vertices have 2 + cells*2 supports */
5927     for (f = fStart; f < fEnd; ++f) {
5928       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5929       const PetscInt *cone, *support;
5930       PetscInt        size, s;
5931 
5932       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5933       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5934       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5935       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5936       for (s = 0; s < size; ++s) {
5937         PetscInt r = 0;
5938 
5939         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5940         if      (cone[1] == f) r = 1;
5941         else if (cone[2] == f) r = 2;
5942         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5943         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5944       }
5945       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5946 #if 1
5947       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5948       for (p = 0; p < 2+size*2; ++p) {
5949         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);
5950       }
5951 #endif
5952     }
5953     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5954     break;
5955   case 2:
5956     /* Hex 2D */
5957     /*
5958      3---------2---------2
5959      |         |         |
5960      |    D    2    C    |
5961      |         |         |
5962      3----3----0----1----1
5963      |         |         |
5964      |    A    0    B    |
5965      |         |         |
5966      0---------0---------1
5967      */
5968     /* All cells have 4 faces */
5969     for (c = cStart; c < cEnd; ++c) {
5970       const PetscInt  newp = (c - cStart)*4;
5971       const PetscInt *cone, *ornt;
5972       PetscInt        coneNew[4], orntNew[4];
5973 
5974       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5975       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5976       /* A quad */
5977       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5978       orntNew[0] = ornt[0];
5979       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5980       orntNew[1] = 0;
5981       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5982       orntNew[2] = -2;
5983       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5984       orntNew[3] = ornt[3];
5985       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5986       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5987 #if 1
5988       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);
5989       for (p = 0; p < 4; ++p) {
5990         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);
5991       }
5992 #endif
5993       /* B quad */
5994       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5995       orntNew[0] = ornt[0];
5996       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5997       orntNew[1] = ornt[1];
5998       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5999       orntNew[2] = 0;
6000       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6001       orntNew[3] = -2;
6002       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6003       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6004 #if 1
6005       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);
6006       for (p = 0; p < 4; ++p) {
6007         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);
6008       }
6009 #endif
6010       /* C quad */
6011       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6012       orntNew[0] = -2;
6013       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6014       orntNew[1] = ornt[1];
6015       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6016       orntNew[2] = ornt[2];
6017       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6018       orntNew[3] = 0;
6019       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6020       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6021 #if 1
6022       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);
6023       for (p = 0; p < 4; ++p) {
6024         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);
6025       }
6026 #endif
6027       /* D quad */
6028       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6029       orntNew[0] = 0;
6030       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6031       orntNew[1] = -2;
6032       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6033       orntNew[2] = ornt[2];
6034       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6035       orntNew[3] = ornt[3];
6036       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6037       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6038 #if 1
6039       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);
6040       for (p = 0; p < 4; ++p) {
6041         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);
6042       }
6043 #endif
6044     }
6045     /* Split faces have 2 vertices and the same cells as the parent */
6046     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6047     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6048     for (f = fStart; f < fEnd; ++f) {
6049       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6050 
6051       for (r = 0; r < 2; ++r) {
6052         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6053         const PetscInt *cone, *support;
6054         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6055 
6056         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6057         coneNew[0]       = vStartNew + (cone[0] - vStart);
6058         coneNew[1]       = vStartNew + (cone[1] - vStart);
6059         coneNew[(r+1)%2] = newv;
6060         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6061 #if 1
6062         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6063         for (p = 0; p < 2; ++p) {
6064           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);
6065         }
6066 #endif
6067         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6068         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6069         for (s = 0; s < supportSize; ++s) {
6070           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6071           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6072           for (c = 0; c < coneSize; ++c) {
6073             if (cone[c] == f) break;
6074           }
6075           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6076         }
6077         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6078 #if 1
6079         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6080         for (p = 0; p < supportSize; ++p) {
6081           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);
6082         }
6083 #endif
6084       }
6085     }
6086     /* Interior faces have 2 vertices and 2 cells */
6087     for (c = cStart; c < cEnd; ++c) {
6088       const PetscInt *cone;
6089       PetscInt        coneNew[2], supportNew[2];
6090 
6091       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6092       for (r = 0; r < 4; ++r) {
6093         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6094 
6095         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6096         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6097         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6098 #if 1
6099         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6100         for (p = 0; p < 2; ++p) {
6101           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);
6102         }
6103 #endif
6104         supportNew[0] = (c - cStart)*4 + r;
6105         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6106         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6107 #if 1
6108         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6109         for (p = 0; p < 2; ++p) {
6110           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);
6111         }
6112 #endif
6113       }
6114     }
6115     /* Old vertices have identical supports */
6116     for (v = vStart; v < vEnd; ++v) {
6117       const PetscInt  newp = vStartNew + (v - vStart);
6118       const PetscInt *support, *cone;
6119       PetscInt        size, s;
6120 
6121       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6122       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6123       for (s = 0; s < size; ++s) {
6124         PetscInt r = 0;
6125 
6126         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6127         if (cone[1] == v) r = 1;
6128         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6129       }
6130       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6131 #if 1
6132       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6133       for (p = 0; p < size; ++p) {
6134         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);
6135       }
6136 #endif
6137     }
6138     /* Face vertices have 2 + cells supports */
6139     for (f = fStart; f < fEnd; ++f) {
6140       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6141       const PetscInt *cone, *support;
6142       PetscInt        size, s;
6143 
6144       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6145       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6146       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6147       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6148       for (s = 0; s < size; ++s) {
6149         PetscInt r = 0;
6150 
6151         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6152         if      (cone[1] == f) r = 1;
6153         else if (cone[2] == f) r = 2;
6154         else if (cone[3] == f) r = 3;
6155         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6156       }
6157       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6158 #if 1
6159       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6160       for (p = 0; p < 2+size; ++p) {
6161         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);
6162       }
6163 #endif
6164     }
6165     /* Cell vertices have 4 supports */
6166     for (c = cStart; c < cEnd; ++c) {
6167       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6168       PetscInt       supportNew[4];
6169 
6170       for (r = 0; r < 4; ++r) {
6171         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6172       }
6173       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6174     }
6175     break;
6176   case 3:
6177     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6178     cMax = PetscMin(cEnd, cMax);
6179     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6180     fMax = PetscMin(fEnd, fMax);
6181     /* Interior cells have 3 faces */
6182     for (c = cStart; c < cMax; ++c) {
6183       const PetscInt  newp = cStartNew + (c - cStart)*4;
6184       const PetscInt *cone, *ornt;
6185       PetscInt        coneNew[3], orntNew[3];
6186 
6187       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6188       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6189       /* A triangle */
6190       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6191       orntNew[0] = ornt[0];
6192       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6193       orntNew[1] = -2;
6194       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6195       orntNew[2] = ornt[2];
6196       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6197       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6198 #if 1
6199       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);
6200       for (p = 0; p < 3; ++p) {
6201         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);
6202       }
6203 #endif
6204       /* B triangle */
6205       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6206       orntNew[0] = ornt[0];
6207       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6208       orntNew[1] = ornt[1];
6209       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6210       orntNew[2] = -2;
6211       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6212       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6213 #if 1
6214       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);
6215       for (p = 0; p < 3; ++p) {
6216         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);
6217       }
6218 #endif
6219       /* C triangle */
6220       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6221       orntNew[0] = -2;
6222       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6223       orntNew[1] = ornt[1];
6224       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6225       orntNew[2] = ornt[2];
6226       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6227       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6228 #if 1
6229       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);
6230       for (p = 0; p < 3; ++p) {
6231         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);
6232       }
6233 #endif
6234       /* D triangle */
6235       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6236       orntNew[0] = 0;
6237       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6238       orntNew[1] = 0;
6239       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6240       orntNew[2] = 0;
6241       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6242       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6243 #if 1
6244       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);
6245       for (p = 0; p < 3; ++p) {
6246         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);
6247       }
6248 #endif
6249     }
6250     /*
6251      2----3----3
6252      |         |
6253      |    B    |
6254      |         |
6255      0----4--- 1
6256      |         |
6257      |    A    |
6258      |         |
6259      0----2----1
6260      */
6261     /* Hybrid cells have 4 faces */
6262     for (c = cMax; c < cEnd; ++c) {
6263       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6264       const PetscInt *cone, *ornt;
6265       PetscInt        coneNew[4], orntNew[4];
6266 
6267       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6268       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6269       /* A quad */
6270       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6271       orntNew[0] = ornt[0];
6272       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6273       orntNew[1] = ornt[1];
6274       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6275       orntNew[2] = 0;
6276       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6277       orntNew[3] = 0;
6278       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6279       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6280 #if 1
6281       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);
6282       for (p = 0; p < 4; ++p) {
6283         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);
6284       }
6285 #endif
6286       /* B quad */
6287       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6288       orntNew[0] = ornt[0];
6289       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6290       orntNew[1] = ornt[1];
6291       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6292       orntNew[2] = 0;
6293       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6294       orntNew[3] = 0;
6295       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6296       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6297 #if 1
6298       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);
6299       for (p = 0; p < 4; ++p) {
6300         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);
6301       }
6302 #endif
6303     }
6304     /* Interior split faces have 2 vertices and the same cells as the parent */
6305     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6306     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6307     for (f = fStart; f < fMax; ++f) {
6308       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6309 
6310       for (r = 0; r < 2; ++r) {
6311         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6312         const PetscInt *cone, *support;
6313         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6314 
6315         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6316         coneNew[0]       = vStartNew + (cone[0] - vStart);
6317         coneNew[1]       = vStartNew + (cone[1] - vStart);
6318         coneNew[(r+1)%2] = newv;
6319         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6320 #if 1
6321         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6322         for (p = 0; p < 2; ++p) {
6323           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);
6324         }
6325 #endif
6326         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6327         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6328         for (s = 0; s < supportSize; ++s) {
6329           if (support[s] >= cMax) {
6330             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6331           } else {
6332             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6333             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6334             for (c = 0; c < coneSize; ++c) {
6335               if (cone[c] == f) break;
6336             }
6337             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6338           }
6339         }
6340         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6341 #if 1
6342         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6343         for (p = 0; p < supportSize; ++p) {
6344           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);
6345         }
6346 #endif
6347       }
6348     }
6349     /* Interior cell faces have 2 vertices and 2 cells */
6350     for (c = cStart; c < cMax; ++c) {
6351       const PetscInt *cone;
6352 
6353       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6354       for (r = 0; r < 3; ++r) {
6355         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6356         PetscInt       coneNew[2];
6357         PetscInt       supportNew[2];
6358 
6359         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6360         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6361         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6362 #if 1
6363         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6364         for (p = 0; p < 2; ++p) {
6365           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);
6366         }
6367 #endif
6368         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6369         supportNew[1] = (c - cStart)*4 + 3;
6370         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6371 #if 1
6372         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6373         for (p = 0; p < 2; ++p) {
6374           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);
6375         }
6376 #endif
6377       }
6378     }
6379     /* Interior hybrid faces have 2 vertices and the same cells */
6380     for (f = fMax; f < fEnd; ++f) {
6381       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6382       const PetscInt *cone;
6383       const PetscInt *support;
6384       PetscInt        coneNew[2];
6385       PetscInt        supportNew[2];
6386       PetscInt        size, s, r;
6387 
6388       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6389       coneNew[0] = vStartNew + (cone[0] - vStart);
6390       coneNew[1] = vStartNew + (cone[1] - vStart);
6391       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6392 #if 1
6393       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6394       for (p = 0; p < 2; ++p) {
6395         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);
6396       }
6397 #endif
6398       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6399       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6400       for (s = 0; s < size; ++s) {
6401         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6402         for (r = 0; r < 2; ++r) {
6403           if (cone[r+2] == f) break;
6404         }
6405         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6406       }
6407       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6408 #if 1
6409       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6410       for (p = 0; p < size; ++p) {
6411         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);
6412       }
6413 #endif
6414     }
6415     /* Cell hybrid faces have 2 vertices and 2 cells */
6416     for (c = cMax; c < cEnd; ++c) {
6417       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6418       const PetscInt *cone;
6419       PetscInt        coneNew[2];
6420       PetscInt        supportNew[2];
6421 
6422       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6423       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6424       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6425       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6426 #if 1
6427       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6428       for (p = 0; p < 2; ++p) {
6429         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);
6430       }
6431 #endif
6432       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6433       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6434       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6435 #if 1
6436       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6437       for (p = 0; p < 2; ++p) {
6438         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);
6439       }
6440 #endif
6441     }
6442     /* Old vertices have identical supports */
6443     for (v = vStart; v < vEnd; ++v) {
6444       const PetscInt  newp = vStartNew + (v - vStart);
6445       const PetscInt *support, *cone;
6446       PetscInt        size, s;
6447 
6448       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6449       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6450       for (s = 0; s < size; ++s) {
6451         if (support[s] >= fMax) {
6452           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6453         } else {
6454           PetscInt r = 0;
6455 
6456           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6457           if (cone[1] == v) r = 1;
6458           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6459         }
6460       }
6461       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6462 #if 1
6463       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6464       for (p = 0; p < size; ++p) {
6465         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);
6466       }
6467 #endif
6468     }
6469     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6470     for (f = fStart; f < fMax; ++f) {
6471       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6472       const PetscInt *cone, *support;
6473       PetscInt        size, newSize = 2, s;
6474 
6475       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6476       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6477       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6478       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6479       for (s = 0; s < size; ++s) {
6480         PetscInt r = 0;
6481 
6482         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6483         if (support[s] >= cMax) {
6484           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6485 
6486           newSize += 1;
6487         } else {
6488           if      (cone[1] == f) r = 1;
6489           else if (cone[2] == f) r = 2;
6490           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6491           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6492 
6493           newSize += 2;
6494         }
6495       }
6496       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6497 #if 1
6498       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6499       for (p = 0; p < newSize; ++p) {
6500         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);
6501       }
6502 #endif
6503     }
6504     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6505     break;
6506   default:
6507     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6508   }
6509   PetscFunctionReturn(0);
6510 }
6511 
6512 #undef __FUNCT__
6513 #define __FUNCT__ "CellRefinerSetCoordinates"
6514 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6515 {
6516   PetscSection   coordSection, coordSectionNew;
6517   Vec            coordinates, coordinatesNew;
6518   PetscScalar   *coords, *coordsNew;
6519   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6520   PetscErrorCode ierr;
6521 
6522   PetscFunctionBegin;
6523   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6525   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6526   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6527   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6528   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6529   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6530   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6531   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6532   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6533   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6534   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6535   if (fMax < 0) fMax = fEnd;
6536   switch (refiner) {
6537   case 1:
6538   case 2:
6539   case 3:
6540     /* Simplicial and Hex 2D */
6541     /* All vertices have the dim coordinates */
6542     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6543       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6544       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6545     }
6546     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6547     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6548     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6549     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6550     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6551     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6552     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6553     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6554     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6555     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6556     /* Old vertices have the same coordinates */
6557     for (v = vStart; v < vEnd; ++v) {
6558       const PetscInt newv = vStartNew + (v - vStart);
6559       PetscInt       off, offnew, d;
6560 
6561       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6562       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6563       for (d = 0; d < dim; ++d) {
6564         coordsNew[offnew+d] = coords[off+d];
6565       }
6566     }
6567     /* Face vertices have the average of endpoint coordinates */
6568     for (f = fStart; f < fMax; ++f) {
6569       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6570       const PetscInt *cone;
6571       PetscInt        coneSize, offA, offB, offnew, d;
6572 
6573       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6574       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6575       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6576       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6577       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6578       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6579       for (d = 0; d < dim; ++d) {
6580         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6581       }
6582     }
6583     /* Just Hex 2D */
6584     if (refiner == 2) {
6585       /* Cell vertices have the average of corner coordinates */
6586       for (c = cStart; c < cEnd; ++c) {
6587         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6588         PetscInt      *cone = NULL;
6589         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6590 
6591         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6592         for (p = 0; p < closureSize*2; p += 2) {
6593           const PetscInt point = cone[p];
6594           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6595         }
6596         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6597         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6598         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6599         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6600         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6601         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6602         for (d = 0; d < dim; ++d) {
6603           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6604         }
6605         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6606       }
6607     }
6608     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6609     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6610     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6611     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6612     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6613     break;
6614   default:
6615     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6616   }
6617   PetscFunctionReturn(0);
6618 }
6619 
6620 #undef __FUNCT__
6621 #define __FUNCT__ "DMPlexCreateProcessSF"
6622 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6623 {
6624   PetscInt           numRoots, numLeaves, l;
6625   const PetscInt    *localPoints;
6626   const PetscSFNode *remotePoints;
6627   PetscInt          *localPointsNew;
6628   PetscSFNode       *remotePointsNew;
6629   PetscInt          *ranks, *ranksNew;
6630   PetscErrorCode     ierr;
6631 
6632   PetscFunctionBegin;
6633   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6634   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6635   for (l = 0; l < numLeaves; ++l) {
6636     ranks[l] = remotePoints[l].rank;
6637   }
6638   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6639   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6640   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6641   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6642   for (l = 0; l < numLeaves; ++l) {
6643     ranksNew[l]              = ranks[l];
6644     localPointsNew[l]        = l;
6645     remotePointsNew[l].index = 0;
6646     remotePointsNew[l].rank  = ranksNew[l];
6647   }
6648   ierr = PetscFree(ranks);CHKERRQ(ierr);
6649   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6650   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6651   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6652   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6653   PetscFunctionReturn(0);
6654 }
6655 
6656 #undef __FUNCT__
6657 #define __FUNCT__ "CellRefinerCreateSF"
6658 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6659 {
6660   PetscSF            sf, sfNew, sfProcess;
6661   IS                 processRanks;
6662   MPI_Datatype       depthType;
6663   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6664   const PetscInt    *localPoints, *neighbors;
6665   const PetscSFNode *remotePoints;
6666   PetscInt          *localPointsNew;
6667   PetscSFNode       *remotePointsNew;
6668   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6669   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6670   PetscErrorCode     ierr;
6671 
6672   PetscFunctionBegin;
6673   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6674   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6675   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6676   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6677   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6678   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6679   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6680   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6681   switch (refiner) {
6682   case 3:
6683     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6684     cMax = PetscMin(cEnd, cMax);
6685     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6686     fMax = PetscMin(fEnd, fMax);
6687   }
6688   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6689   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6690   /* Caculate size of new SF */
6691   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6692   if (numRoots < 0) PetscFunctionReturn(0);
6693   for (l = 0; l < numLeaves; ++l) {
6694     const PetscInt p = localPoints[l];
6695 
6696     switch (refiner) {
6697     case 1:
6698       /* Simplicial 2D */
6699       if ((p >= vStart) && (p < vEnd)) {
6700         /* Old vertices stay the same */
6701         ++numLeavesNew;
6702       } else if ((p >= fStart) && (p < fEnd)) {
6703         /* Old faces add new faces and vertex */
6704         numLeavesNew += 1 + 2;
6705       } else if ((p >= cStart) && (p < cEnd)) {
6706         /* Old cells add new cells and interior faces */
6707         numLeavesNew += 4 + 3;
6708       }
6709       break;
6710     case 2:
6711       /* Hex 2D */
6712       if ((p >= vStart) && (p < vEnd)) {
6713         /* Old vertices stay the same */
6714         ++numLeavesNew;
6715       } else if ((p >= fStart) && (p < fEnd)) {
6716         /* Old faces add new faces and vertex */
6717         numLeavesNew += 1 + 2;
6718       } else if ((p >= cStart) && (p < cEnd)) {
6719         /* Old cells add new cells and interior faces */
6720         numLeavesNew += 4 + 4;
6721       }
6722       break;
6723     default:
6724       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6725     }
6726   }
6727   /* Communicate depthSizes for each remote rank */
6728   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6729   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6730   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6731   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);
6732   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6733   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6734   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6735   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6736   for (n = 0; n < numNeighbors; ++n) {
6737     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6738   }
6739   depthSizeOld[depth]   = cMax;
6740   depthSizeOld[0]       = vMax;
6741   depthSizeOld[depth-1] = fMax;
6742   depthSizeOld[1]       = eMax;
6743 
6744   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6745   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6746 
6747   depthSizeOld[depth]   = cEnd - cStart;
6748   depthSizeOld[0]       = vEnd - vStart;
6749   depthSizeOld[depth-1] = fEnd - fStart;
6750   depthSizeOld[1]       = eEnd - eStart;
6751 
6752   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6753   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6754   for (n = 0; n < numNeighbors; ++n) {
6755     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6756   }
6757   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6758   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6759   /* Calculate new point SF */
6760   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6761   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6762   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6763   for (l = 0, m = 0; l < numLeaves; ++l) {
6764     PetscInt    p     = localPoints[l];
6765     PetscInt    rp    = remotePoints[l].index, n;
6766     PetscMPIInt rrank = remotePoints[l].rank;
6767 
6768     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6769     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6770     switch (refiner) {
6771     case 1:
6772       /* Simplicial 2D */
6773       if ((p >= vStart) && (p < vEnd)) {
6774         /* Old vertices stay the same */
6775         localPointsNew[m]        = vStartNew     + (p  - vStart);
6776         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6777         remotePointsNew[m].rank  = rrank;
6778         ++m;
6779       } else if ((p >= fStart) && (p < fEnd)) {
6780         /* Old faces add new faces and vertex */
6781         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6782         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6783         remotePointsNew[m].rank  = rrank;
6784         ++m;
6785         for (r = 0; r < 2; ++r, ++m) {
6786           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6787           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6788           remotePointsNew[m].rank  = rrank;
6789         }
6790       } else if ((p >= cStart) && (p < cEnd)) {
6791         /* Old cells add new cells and interior faces */
6792         for (r = 0; r < 4; ++r, ++m) {
6793           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6794           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6795           remotePointsNew[m].rank  = rrank;
6796         }
6797         for (r = 0; r < 3; ++r, ++m) {
6798           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6799           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6800           remotePointsNew[m].rank  = rrank;
6801         }
6802       }
6803       break;
6804     case 2:
6805       /* Hex 2D */
6806       if ((p >= vStart) && (p < vEnd)) {
6807         /* Old vertices stay the same */
6808         localPointsNew[m]        = vStartNew     + (p  - vStart);
6809         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6810         remotePointsNew[m].rank  = rrank;
6811         ++m;
6812       } else if ((p >= fStart) && (p < fEnd)) {
6813         /* Old faces add new faces and vertex */
6814         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6815         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6816         remotePointsNew[m].rank  = rrank;
6817         ++m;
6818         for (r = 0; r < 2; ++r, ++m) {
6819           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6820           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6821           remotePointsNew[m].rank  = rrank;
6822         }
6823       } else if ((p >= cStart) && (p < cEnd)) {
6824         /* Old cells add new cells and interior faces */
6825         for (r = 0; r < 4; ++r, ++m) {
6826           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6827           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6828           remotePointsNew[m].rank  = rrank;
6829         }
6830         for (r = 0; r < 4; ++r, ++m) {
6831           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6832           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6833           remotePointsNew[m].rank  = rrank;
6834         }
6835       }
6836       break;
6837     case 3:
6838       /* Hybrid simplicial 2D */
6839       if ((p >= vStart) && (p < vEnd)) {
6840         /* Old vertices stay the same */
6841         localPointsNew[m]        = vStartNew     + (p  - vStart);
6842         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6843         remotePointsNew[m].rank  = rrank;
6844         ++m;
6845       } else if ((p >= fStart) && (p < fMax)) {
6846         /* Old interior faces add new faces and vertex */
6847         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6848         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6849         remotePointsNew[m].rank  = rrank;
6850         ++m;
6851         for (r = 0; r < 2; ++r, ++m) {
6852           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6853           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6854           remotePointsNew[m].rank  = rrank;
6855         }
6856       } else if ((p >= fMax) && (p < fEnd)) {
6857         /* Old hybrid faces stay the same */
6858         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6859         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6860         remotePointsNew[m].rank  = rrank;
6861         ++m;
6862       } else if ((p >= cStart) && (p < cMax)) {
6863         /* Old interior cells add new cells and interior faces */
6864         for (r = 0; r < 4; ++r, ++m) {
6865           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6866           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6867           remotePointsNew[m].rank  = rrank;
6868         }
6869         for (r = 0; r < 3; ++r, ++m) {
6870           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6871           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6872           remotePointsNew[m].rank  = rrank;
6873         }
6874       } else if ((p >= cStart) && (p < cMax)) {
6875         /* Old hybrid cells add new cells and hybrid face */
6876         for (r = 0; r < 2; ++r, ++m) {
6877           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6878           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6879           remotePointsNew[m].rank  = rrank;
6880         }
6881         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6882         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]);
6883         remotePointsNew[m].rank  = rrank;
6884         ++m;
6885       }
6886       break;
6887     default:
6888       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6889     }
6890   }
6891   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6892   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6893   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6894   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6895   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6896   PetscFunctionReturn(0);
6897 }
6898 
6899 #undef __FUNCT__
6900 #define __FUNCT__ "CellRefinerCreateLabels"
6901 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6902 {
6903   PetscInt       numLabels, l;
6904   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6905   PetscErrorCode ierr;
6906 
6907   PetscFunctionBegin;
6908   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6909   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6910   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6911   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6912 
6913   cStartNew = 0;
6914   vStartNew = depthSize[2];
6915   fStartNew = depthSize[2] + depthSize[0];
6916 
6917   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6918   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6919   switch (refiner) {
6920   case 3:
6921     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6922     cMax = PetscMin(cEnd, cMax);
6923     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6924     fMax = PetscMin(fEnd, fMax);
6925   }
6926   for (l = 0; l < numLabels; ++l) {
6927     DMLabel         label, labelNew;
6928     const char     *lname;
6929     PetscBool       isDepth;
6930     IS              valueIS;
6931     const PetscInt *values;
6932     PetscInt        numValues, val;
6933 
6934     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6935     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6936     if (isDepth) continue;
6937     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6938     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6939     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6940     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6941     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6942     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6943     for (val = 0; val < numValues; ++val) {
6944       IS              pointIS;
6945       const PetscInt *points;
6946       PetscInt        numPoints, n;
6947 
6948       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6949       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6950       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6951       for (n = 0; n < numPoints; ++n) {
6952         const PetscInt p = points[n];
6953         switch (refiner) {
6954         case 1:
6955           /* Simplicial 2D */
6956           if ((p >= vStart) && (p < vEnd)) {
6957             /* Old vertices stay the same */
6958             newp = vStartNew + (p - vStart);
6959             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6960           } else if ((p >= fStart) && (p < fEnd)) {
6961             /* Old faces add new faces and vertex */
6962             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6963             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6964             for (r = 0; r < 2; ++r) {
6965               newp = fStartNew + (p - fStart)*2 + r;
6966               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6967             }
6968           } else if ((p >= cStart) && (p < cEnd)) {
6969             /* Old cells add new cells and interior faces */
6970             for (r = 0; r < 4; ++r) {
6971               newp = cStartNew + (p - cStart)*4 + r;
6972               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6973             }
6974             for (r = 0; r < 3; ++r) {
6975               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6976               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6977             }
6978           }
6979           break;
6980         case 2:
6981           /* Hex 2D */
6982           if ((p >= vStart) && (p < vEnd)) {
6983             /* Old vertices stay the same */
6984             newp = vStartNew + (p - vStart);
6985             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6986           } else if ((p >= fStart) && (p < fEnd)) {
6987             /* Old faces add new faces and vertex */
6988             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6989             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6990             for (r = 0; r < 2; ++r) {
6991               newp = fStartNew + (p - fStart)*2 + r;
6992               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6993             }
6994           } else if ((p >= cStart) && (p < cEnd)) {
6995             /* Old cells add new cells and interior faces and vertex */
6996             for (r = 0; r < 4; ++r) {
6997               newp = cStartNew + (p - cStart)*4 + r;
6998               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6999             }
7000             for (r = 0; r < 4; ++r) {
7001               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7002               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7003             }
7004             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7005             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7006           }
7007           break;
7008         case 3:
7009           /* Hybrid simplicial 2D */
7010           if ((p >= vStart) && (p < vEnd)) {
7011             /* Old vertices stay the same */
7012             newp = vStartNew + (p - vStart);
7013             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7014           } else if ((p >= fStart) && (p < fMax)) {
7015             /* Old interior faces add new faces and vertex */
7016             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7017             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7018             for (r = 0; r < 2; ++r) {
7019               newp = fStartNew + (p - fStart)*2 + r;
7020               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7021             }
7022           } else if ((p >= fMax) && (p < fEnd)) {
7023             /* Old hybrid faces stay the same */
7024             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7025             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7026           } else if ((p >= cStart) && (p < cMax)) {
7027             /* Old interior cells add new cells and interior faces */
7028             for (r = 0; r < 4; ++r) {
7029               newp = cStartNew + (p - cStart)*4 + r;
7030               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7031             }
7032             for (r = 0; r < 3; ++r) {
7033               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7034               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7035             }
7036           } else if ((p >= cMax) && (p < cEnd)) {
7037             /* Old hybrid cells add new cells and hybrid face */
7038             for (r = 0; r < 2; ++r) {
7039               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7040               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7041             }
7042             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7043             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7044           }
7045           break;
7046         default:
7047           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7048         }
7049       }
7050       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7051       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7052     }
7053     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7054     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7055     if (0) {
7056       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7057       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7058       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7059     }
7060   }
7061   PetscFunctionReturn(0);
7062 }
7063 
7064 #undef __FUNCT__
7065 #define __FUNCT__ "DMPlexRefine_Uniform"
7066 /* This will only work for interpolated meshes */
7067 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7068 {
7069   DM             rdm;
7070   PetscInt      *depthSize;
7071   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7072   PetscErrorCode ierr;
7073 
7074   PetscFunctionBegin;
7075   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7076   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7077   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7078   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7079   /* Calculate number of new points of each depth */
7080   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7081   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7082   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7083   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7084   /* Step 1: Set chart */
7085   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7086   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7087   /* Step 2: Set cone/support sizes */
7088   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7089   /* Step 3: Setup refined DM */
7090   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7091   /* Step 4: Set cones and supports */
7092   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7093   /* Step 5: Stratify */
7094   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7095   /* Step 6: Set coordinates for vertices */
7096   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7097   /* Step 7: Create pointSF */
7098   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7099   /* Step 8: Create labels */
7100   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7101   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7102 
7103   *dmRefined = rdm;
7104   PetscFunctionReturn(0);
7105 }
7106 
7107 #undef __FUNCT__
7108 #define __FUNCT__ "DMPlexSetRefinementUniform"
7109 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7110 {
7111   DM_Plex *mesh = (DM_Plex*) dm->data;
7112 
7113   PetscFunctionBegin;
7114   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7115   mesh->refinementUniform = refinementUniform;
7116   PetscFunctionReturn(0);
7117 }
7118 
7119 #undef __FUNCT__
7120 #define __FUNCT__ "DMPlexGetRefinementUniform"
7121 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7122 {
7123   DM_Plex *mesh = (DM_Plex*) dm->data;
7124 
7125   PetscFunctionBegin;
7126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7127   PetscValidPointer(refinementUniform,  2);
7128   *refinementUniform = mesh->refinementUniform;
7129   PetscFunctionReturn(0);
7130 }
7131 
7132 #undef __FUNCT__
7133 #define __FUNCT__ "DMPlexSetRefinementLimit"
7134 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7135 {
7136   DM_Plex *mesh = (DM_Plex*) dm->data;
7137 
7138   PetscFunctionBegin;
7139   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7140   mesh->refinementLimit = refinementLimit;
7141   PetscFunctionReturn(0);
7142 }
7143 
7144 #undef __FUNCT__
7145 #define __FUNCT__ "DMPlexGetRefinementLimit"
7146 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7147 {
7148   DM_Plex *mesh = (DM_Plex*) dm->data;
7149 
7150   PetscFunctionBegin;
7151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7152   PetscValidPointer(refinementLimit,  2);
7153   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7154   *refinementLimit = mesh->refinementLimit;
7155   PetscFunctionReturn(0);
7156 }
7157 
7158 #undef __FUNCT__
7159 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7160 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7161 {
7162   PetscInt       dim, cStart, coneSize, cMax;
7163   PetscErrorCode ierr;
7164 
7165   PetscFunctionBegin;
7166   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7167   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7168   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7169   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7170   switch (dim) {
7171   case 2:
7172     switch (coneSize) {
7173     case 3:
7174       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7175       else *cellRefiner = 1; /* Triangular */
7176       break;
7177     case 4:
7178       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7179       else *cellRefiner = 2; /* Quadrilateral */
7180       break;
7181     default:
7182       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7183     }
7184     break;
7185   default:
7186     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7187   }
7188   PetscFunctionReturn(0);
7189 }
7190 
7191 #undef __FUNCT__
7192 #define __FUNCT__ "DMRefine_Plex"
7193 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7194 {
7195   PetscReal      refinementLimit;
7196   PetscInt       dim, cStart, cEnd;
7197   char           genname[1024], *name = NULL;
7198   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7199   PetscErrorCode ierr;
7200 
7201   PetscFunctionBegin;
7202   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7203   if (isUniform) {
7204     CellRefiner cellRefiner;
7205 
7206     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7207     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7208     PetscFunctionReturn(0);
7209   }
7210   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7211   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7212   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7213   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7214   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7215   if (flg) name = genname;
7216   if (name) {
7217     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7218     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7219     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7220   }
7221   switch (dim) {
7222   case 2:
7223     if (!name || isTriangle) {
7224 #if defined(PETSC_HAVE_TRIANGLE)
7225       double  *maxVolumes;
7226       PetscInt c;
7227 
7228       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7229       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7230       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7231 #else
7232       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7233 #endif
7234     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7235     break;
7236   case 3:
7237     if (!name || isCTetgen) {
7238 #if defined(PETSC_HAVE_CTETGEN)
7239       PetscReal *maxVolumes;
7240       PetscInt   c;
7241 
7242       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7243       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7244       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7245 #else
7246       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7247 #endif
7248     } else if (isTetgen) {
7249 #if defined(PETSC_HAVE_TETGEN)
7250       double  *maxVolumes;
7251       PetscInt c;
7252 
7253       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7254       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7255       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7256 #else
7257       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7258 #endif
7259     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7260     break;
7261   default:
7262     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7263   }
7264   PetscFunctionReturn(0);
7265 }
7266 
7267 #undef __FUNCT__
7268 #define __FUNCT__ "DMPlexGetDepth"
7269 /*@
7270   DMPlexGetDepth - get the number of strata
7271 
7272   Not Collective
7273 
7274   Input Parameters:
7275 . dm           - The DMPlex object
7276 
7277   Output Parameters:
7278 . depth - number of strata
7279 
7280   Level: developer
7281 
7282   Notes:
7283   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7284 
7285 .keywords: mesh, points
7286 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7287 @*/
7288 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7289 {
7290   PetscInt       d;
7291   PetscErrorCode ierr;
7292 
7293   PetscFunctionBegin;
7294   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7295   PetscValidPointer(depth, 2);
7296   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7297   *depth = d-1;
7298   PetscFunctionReturn(0);
7299 }
7300 
7301 #undef __FUNCT__
7302 #define __FUNCT__ "DMPlexGetDepthStratum"
7303 /*@
7304   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7305 
7306   Not Collective
7307 
7308   Input Parameters:
7309 + dm           - The DMPlex object
7310 - stratumValue - The requested depth
7311 
7312   Output Parameters:
7313 + start - The first point at this depth
7314 - end   - One beyond the last point at this depth
7315 
7316   Level: developer
7317 
7318 .keywords: mesh, points
7319 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7320 @*/
7321 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7322 {
7323   DM_Plex       *mesh = (DM_Plex*) dm->data;
7324   DMLabel        next  = mesh->labels;
7325   PetscBool      flg   = PETSC_FALSE;
7326   PetscInt       depth;
7327   PetscErrorCode ierr;
7328 
7329   PetscFunctionBegin;
7330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7331   if (stratumValue < 0) {
7332     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7333     PetscFunctionReturn(0);
7334   } else {
7335     PetscInt pStart, pEnd;
7336 
7337     if (start) *start = 0;
7338     if (end)   *end   = 0;
7339     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7340     if (pStart == pEnd) PetscFunctionReturn(0);
7341   }
7342   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7343   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7344   /* We should have a generic GetLabel() and a Label class */
7345   while (next) {
7346     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7347     if (flg) break;
7348     next = next->next;
7349   }
7350   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7351   depth = stratumValue;
7352   if ((depth < 0) || (depth >= next->numStrata)) {
7353     if (start) *start = 0;
7354     if (end)   *end   = 0;
7355   } else {
7356     if (start) *start = next->points[next->stratumOffsets[depth]];
7357     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7358   }
7359   PetscFunctionReturn(0);
7360 }
7361 
7362 #undef __FUNCT__
7363 #define __FUNCT__ "DMPlexGetHeightStratum"
7364 /*@
7365   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7366 
7367   Not Collective
7368 
7369   Input Parameters:
7370 + dm           - The DMPlex object
7371 - stratumValue - The requested height
7372 
7373   Output Parameters:
7374 + start - The first point at this height
7375 - end   - One beyond the last point at this height
7376 
7377   Level: developer
7378 
7379 .keywords: mesh, points
7380 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7381 @*/
7382 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7383 {
7384   DM_Plex       *mesh = (DM_Plex*) dm->data;
7385   DMLabel        next  = mesh->labels;
7386   PetscBool      flg   = PETSC_FALSE;
7387   PetscInt       depth;
7388   PetscErrorCode ierr;
7389 
7390   PetscFunctionBegin;
7391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7392   if (stratumValue < 0) {
7393     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7394   } else {
7395     PetscInt pStart, pEnd;
7396 
7397     if (start) *start = 0;
7398     if (end)   *end   = 0;
7399     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7400     if (pStart == pEnd) PetscFunctionReturn(0);
7401   }
7402   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7403   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7404   /* We should have a generic GetLabel() and a Label class */
7405   while (next) {
7406     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7407     if (flg) break;
7408     next = next->next;
7409   }
7410   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7411   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7412   if ((depth < 0) || (depth >= next->numStrata)) {
7413     if (start) *start = 0;
7414     if (end)   *end   = 0;
7415   } else {
7416     if (start) *start = next->points[next->stratumOffsets[depth]];
7417     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7418   }
7419   PetscFunctionReturn(0);
7420 }
7421 
7422 #undef __FUNCT__
7423 #define __FUNCT__ "DMPlexCreateSectionInitial"
7424 /* Set the number of dof on each point and separate by fields */
7425 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7426 {
7427   PetscInt      *numDofTot;
7428   PetscInt       pStart = 0, pEnd = 0;
7429   PetscInt       p, d, f;
7430   PetscErrorCode ierr;
7431 
7432   PetscFunctionBegin;
7433   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7434   for (d = 0; d <= dim; ++d) {
7435     numDofTot[d] = 0;
7436     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7437   }
7438   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7439   if (numFields > 0) {
7440     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7441     if (numComp) {
7442       for (f = 0; f < numFields; ++f) {
7443         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7444       }
7445     }
7446   }
7447   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7448   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7449   for (d = 0; d <= dim; ++d) {
7450     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7451     for (p = pStart; p < pEnd; ++p) {
7452       for (f = 0; f < numFields; ++f) {
7453         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7454       }
7455       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7456     }
7457   }
7458   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7459   PetscFunctionReturn(0);
7460 }
7461 
7462 #undef __FUNCT__
7463 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7464 /* Set the number of dof on each point and separate by fields
7465    If constDof is PETSC_DETERMINE, constrain every dof on the point
7466 */
7467 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7468 {
7469   PetscInt       numFields;
7470   PetscInt       bc;
7471   PetscErrorCode ierr;
7472 
7473   PetscFunctionBegin;
7474   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7475   for (bc = 0; bc < numBC; ++bc) {
7476     PetscInt        field = 0;
7477     const PetscInt *idx;
7478     PetscInt        n, i;
7479 
7480     if (numFields) field = bcField[bc];
7481     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7482     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7483     for (i = 0; i < n; ++i) {
7484       const PetscInt p        = idx[i];
7485       PetscInt       numConst = constDof;
7486 
7487       /* Constrain every dof on the point */
7488       if (numConst < 0) {
7489         if (numFields) {
7490           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7491         } else {
7492           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7493         }
7494       }
7495       if (numFields) {
7496         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7497       }
7498       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7499     }
7500     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7501   }
7502   PetscFunctionReturn(0);
7503 }
7504 
7505 #undef __FUNCT__
7506 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7507 /* Set the constrained indices on each point and separate by fields */
7508 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7509 {
7510   PetscInt      *maxConstraints;
7511   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7512   PetscErrorCode ierr;
7513 
7514   PetscFunctionBegin;
7515   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7516   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7517   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7518   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7519   for (p = pStart; p < pEnd; ++p) {
7520     PetscInt cdof;
7521 
7522     if (numFields) {
7523       for (f = 0; f < numFields; ++f) {
7524         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7525         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7526       }
7527     } else {
7528       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7529       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7530     }
7531   }
7532   for (f = 0; f < numFields; ++f) {
7533     maxConstraints[numFields] += maxConstraints[f];
7534   }
7535   if (maxConstraints[numFields]) {
7536     PetscInt *indices;
7537 
7538     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7539     for (p = pStart; p < pEnd; ++p) {
7540       PetscInt cdof, d;
7541 
7542       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7543       if (cdof) {
7544         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7545         if (numFields) {
7546           PetscInt numConst = 0, foff = 0;
7547 
7548           for (f = 0; f < numFields; ++f) {
7549             PetscInt cfdof, fdof;
7550 
7551             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7552             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7553             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7554             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7555             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7556             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7557             numConst += cfdof;
7558             foff     += fdof;
7559           }
7560           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7561         } else {
7562           for (d = 0; d < cdof; ++d) indices[d] = d;
7563         }
7564         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7565       }
7566     }
7567     ierr = PetscFree(indices);CHKERRQ(ierr);
7568   }
7569   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7570   PetscFunctionReturn(0);
7571 }
7572 
7573 #undef __FUNCT__
7574 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7575 /* Set the constrained field indices on each point */
7576 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7577 {
7578   const PetscInt *points, *indices;
7579   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7580   PetscErrorCode  ierr;
7581 
7582   PetscFunctionBegin;
7583   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7584   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7585 
7586   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7587   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7588   if (!constraintIndices) {
7589     PetscInt *idx, i;
7590 
7591     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7592     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7593     for (i = 0; i < maxDof; ++i) idx[i] = i;
7594     for (p = 0; p < numPoints; ++p) {
7595       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7596     }
7597     ierr = PetscFree(idx);CHKERRQ(ierr);
7598   } else {
7599     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7600     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7601     for (p = 0; p < numPoints; ++p) {
7602       PetscInt fcdof;
7603 
7604       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7605       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);
7606       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7607     }
7608     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7609   }
7610   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7611   PetscFunctionReturn(0);
7612 }
7613 
7614 #undef __FUNCT__
7615 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7616 /* Set the constrained indices on each point and separate by fields */
7617 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7618 {
7619   PetscInt      *indices;
7620   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7621   PetscErrorCode ierr;
7622 
7623   PetscFunctionBegin;
7624   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7625   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7626   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7627   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7628   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7629   for (p = pStart; p < pEnd; ++p) {
7630     PetscInt cdof, d;
7631 
7632     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7633     if (cdof) {
7634       PetscInt numConst = 0, foff = 0;
7635 
7636       for (f = 0; f < numFields; ++f) {
7637         const PetscInt *fcind;
7638         PetscInt        fdof, fcdof;
7639 
7640         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7641         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7642         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7643         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7644         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7645         foff     += fdof;
7646         numConst += fcdof;
7647       }
7648       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7649       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7650     }
7651   }
7652   ierr = PetscFree(indices);CHKERRQ(ierr);
7653   PetscFunctionReturn(0);
7654 }
7655 
7656 #undef __FUNCT__
7657 #define __FUNCT__ "DMPlexCreateSection"
7658 /*@C
7659   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7660 
7661   Not Collective
7662 
7663   Input Parameters:
7664 + dm        - The DMPlex object
7665 . dim       - The spatial dimension of the problem
7666 . numFields - The number of fields in the problem
7667 . numComp   - An array of size numFields that holds the number of components for each field
7668 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7669 . numBC     - The number of boundary conditions
7670 . bcField   - An array of size numBC giving the field number for each boundry condition
7671 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7672 
7673   Output Parameter:
7674 . section - The PetscSection object
7675 
7676   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
7677   nubmer of dof for field 0 on each edge.
7678 
7679   Level: developer
7680 
7681 .keywords: mesh, elements
7682 .seealso: DMPlexCreate(), PetscSectionCreate()
7683 @*/
7684 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7685 {
7686   PetscErrorCode ierr;
7687 
7688   PetscFunctionBegin;
7689   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7690   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7691   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7692   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7693   {
7694     PetscBool view = PETSC_FALSE;
7695 
7696     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7697     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7698   }
7699   PetscFunctionReturn(0);
7700 }
7701 
7702 #undef __FUNCT__
7703 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7704 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7705 {
7706   PetscSection   section;
7707   PetscErrorCode ierr;
7708 
7709   PetscFunctionBegin;
7710   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7711   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7712   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7713   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7714   PetscFunctionReturn(0);
7715 }
7716 
7717 #undef __FUNCT__
7718 #define __FUNCT__ "DMPlexGetCoordinateSection"
7719 /*@
7720   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7721 
7722   Not Collective
7723 
7724   Input Parameter:
7725 . dm - The DMPlex object
7726 
7727   Output Parameter:
7728 . section - The PetscSection object
7729 
7730   Level: intermediate
7731 
7732 .keywords: mesh, coordinates
7733 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7734 @*/
7735 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7736 {
7737   DM             cdm;
7738   PetscErrorCode ierr;
7739 
7740   PetscFunctionBegin;
7741   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7742   PetscValidPointer(section, 2);
7743   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7744   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7745   PetscFunctionReturn(0);
7746 }
7747 
7748 #undef __FUNCT__
7749 #define __FUNCT__ "DMPlexSetCoordinateSection"
7750 /*@
7751   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7752 
7753   Not Collective
7754 
7755   Input Parameters:
7756 + dm      - The DMPlex object
7757 - section - The PetscSection object
7758 
7759   Level: intermediate
7760 
7761 .keywords: mesh, coordinates
7762 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7763 @*/
7764 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7765 {
7766   DM             cdm;
7767   PetscErrorCode ierr;
7768 
7769   PetscFunctionBegin;
7770   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7771   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7772   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7773   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7774   PetscFunctionReturn(0);
7775 }
7776 
7777 #undef __FUNCT__
7778 #define __FUNCT__ "DMPlexGetConeSection"
7779 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7780 {
7781   DM_Plex *mesh = (DM_Plex*) dm->data;
7782 
7783   PetscFunctionBegin;
7784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7785   if (section) *section = mesh->coneSection;
7786   PetscFunctionReturn(0);
7787 }
7788 
7789 #undef __FUNCT__
7790 #define __FUNCT__ "DMPlexGetCones"
7791 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7792 {
7793   DM_Plex *mesh = (DM_Plex*) dm->data;
7794 
7795   PetscFunctionBegin;
7796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7797   if (cones) *cones = mesh->cones;
7798   PetscFunctionReturn(0);
7799 }
7800 
7801 #undef __FUNCT__
7802 #define __FUNCT__ "DMPlexGetConeOrientations"
7803 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7804 {
7805   DM_Plex *mesh = (DM_Plex*) dm->data;
7806 
7807   PetscFunctionBegin;
7808   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7809   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7810   PetscFunctionReturn(0);
7811 }
7812 
7813 #undef __FUNCT__
7814 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7815 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7816 {
7817   const PetscInt embedDim = 2;
7818   PetscReal      x        = PetscRealPart(point[0]);
7819   PetscReal      y        = PetscRealPart(point[1]);
7820   PetscReal      v0[2], J[4], invJ[4], detJ;
7821   PetscReal      xi, eta;
7822   PetscErrorCode ierr;
7823 
7824   PetscFunctionBegin;
7825   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7826   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7827   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7828 
7829   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7830   else *cell = -1;
7831   PetscFunctionReturn(0);
7832 }
7833 
7834 #undef __FUNCT__
7835 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7836 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7837 {
7838   PetscSection       coordSection;
7839   Vec                coordsLocal;
7840   const PetscScalar *coords;
7841   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7842   PetscReal          x         = PetscRealPart(point[0]);
7843   PetscReal          y         = PetscRealPart(point[1]);
7844   PetscInt           crossings = 0, f;
7845   PetscErrorCode     ierr;
7846 
7847   PetscFunctionBegin;
7848   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7849   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7850   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7851   for (f = 0; f < 4; ++f) {
7852     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7853     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7854     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7855     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7856     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7857     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7858     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7859     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7860     if ((cond1 || cond2)  && above) ++crossings;
7861   }
7862   if (crossings % 2) *cell = c;
7863   else *cell = -1;
7864   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7865   PetscFunctionReturn(0);
7866 }
7867 
7868 #undef __FUNCT__
7869 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7870 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7871 {
7872   const PetscInt embedDim = 3;
7873   PetscReal      v0[3], J[9], invJ[9], detJ;
7874   PetscReal      x = PetscRealPart(point[0]);
7875   PetscReal      y = PetscRealPart(point[1]);
7876   PetscReal      z = PetscRealPart(point[2]);
7877   PetscReal      xi, eta, zeta;
7878   PetscErrorCode ierr;
7879 
7880   PetscFunctionBegin;
7881   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7882   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7883   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7884   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7885 
7886   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7887   else *cell = -1;
7888   PetscFunctionReturn(0);
7889 }
7890 
7891 #undef __FUNCT__
7892 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7893 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7894 {
7895   PetscSection       coordSection;
7896   Vec                coordsLocal;
7897   const PetscScalar *coords;
7898   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7899                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7900   PetscBool          found = PETSC_TRUE;
7901   PetscInt           f;
7902   PetscErrorCode     ierr;
7903 
7904   PetscFunctionBegin;
7905   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7906   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7907   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7908   for (f = 0; f < 6; ++f) {
7909     /* Check the point is under plane */
7910     /*   Get face normal */
7911     PetscReal v_i[3];
7912     PetscReal v_j[3];
7913     PetscReal normal[3];
7914     PetscReal pp[3];
7915     PetscReal dot;
7916 
7917     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7918     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7919     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7920     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7921     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7922     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7923     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7924     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7925     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7926     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7927     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7928     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7929     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7930 
7931     /* Check that projected point is in face (2D location problem) */
7932     if (dot < 0.0) {
7933       found = PETSC_FALSE;
7934       break;
7935     }
7936   }
7937   if (found) *cell = c;
7938   else *cell = -1;
7939   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7940   PetscFunctionReturn(0);
7941 }
7942 
7943 #undef __FUNCT__
7944 #define __FUNCT__ "DMLocatePoints_Plex"
7945 /*
7946  Need to implement using the guess
7947 */
7948 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7949 {
7950   PetscInt       cell = -1 /*, guess = -1*/;
7951   PetscInt       bs, numPoints, p;
7952   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7953   PetscInt      *cells;
7954   PetscScalar   *a;
7955   PetscErrorCode ierr;
7956 
7957   PetscFunctionBegin;
7958   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7959   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7960   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7961   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7962   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7963   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7964   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7965   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);
7966   numPoints /= bs;
7967   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7968   for (p = 0; p < numPoints; ++p) {
7969     const PetscScalar *point = &a[p*bs];
7970 
7971     switch (dim) {
7972     case 2:
7973       for (c = cStart; c < cEnd; ++c) {
7974         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7975         switch (coneSize) {
7976         case 3:
7977           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7978           break;
7979         case 4:
7980           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7981           break;
7982         default:
7983           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7984         }
7985         if (cell >= 0) break;
7986       }
7987       break;
7988     case 3:
7989       for (c = cStart; c < cEnd; ++c) {
7990         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7991         switch (coneSize) {
7992         case 4:
7993           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7994           break;
7995         case 8:
7996           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7997           break;
7998         default:
7999           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8000         }
8001         if (cell >= 0) break;
8002       }
8003       break;
8004     default:
8005       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8006     }
8007     cells[p] = cell;
8008   }
8009   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8010   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8011   PetscFunctionReturn(0);
8012 }
8013 
8014 /******************************** FEM Support **********************************/
8015 
8016 #undef __FUNCT__
8017 #define __FUNCT__ "DMPlexVecGetClosure"
8018 /*@C
8019   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8020 
8021   Not collective
8022 
8023   Input Parameters:
8024 + dm - The DM
8025 . section - The section describing the layout in v, or NULL to use the default section
8026 . v - The local vector
8027 - point - The sieve point in the DM
8028 
8029   Output Parameters:
8030 + csize - The number of values in the closure, or NULL
8031 - values - The array of values, which is a borrowed array and should not be freed
8032 
8033   Level: intermediate
8034 
8035 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8036 @*/
8037 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8038 {
8039   PetscScalar   *array, *vArray;
8040   PetscInt      *points = NULL;
8041   PetscInt       offsets[32];
8042   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8043   PetscErrorCode ierr;
8044 
8045   PetscFunctionBegin;
8046   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8047   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8048   if (!section) {
8049     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8050   }
8051   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8052   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8053   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8054   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8055   /* Compress out points not in the section */
8056   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8057   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8058     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8059       points[q*2]   = points[p];
8060       points[q*2+1] = points[p+1];
8061       ++q;
8062     }
8063   }
8064   numPoints = q;
8065   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8066     PetscInt dof, fdof;
8067 
8068     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8069     for (f = 0; f < numFields; ++f) {
8070       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8071       offsets[f+1] += fdof;
8072     }
8073     size += dof;
8074   }
8075   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8076   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8077   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8078   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8079   for (p = 0; p < numPoints*2; p += 2) {
8080     PetscInt     o = points[p+1];
8081     PetscInt     dof, off, d;
8082     PetscScalar *varr;
8083 
8084     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8085     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8086     varr = &vArray[off];
8087     if (numFields) {
8088       PetscInt fdof, foff, fcomp, f, c;
8089 
8090       for (f = 0, foff = 0; f < numFields; ++f) {
8091         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8092         if (o >= 0) {
8093           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8094             array[offsets[f]] = varr[foff+d];
8095           }
8096         } else {
8097           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8098           for (d = fdof/fcomp-1; d >= 0; --d) {
8099             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8100               array[offsets[f]] = varr[foff+d*fcomp+c];
8101             }
8102           }
8103         }
8104         foff += fdof;
8105       }
8106     } else {
8107       if (o >= 0) {
8108         for (d = 0; d < dof; ++d, ++offsets[0]) {
8109           array[offsets[0]] = varr[d];
8110         }
8111       } else {
8112         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8113           array[offsets[0]] = varr[d];
8114         }
8115       }
8116     }
8117   }
8118   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8119   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8120   if (csize) *csize = size;
8121   *values = array;
8122   PetscFunctionReturn(0);
8123 }
8124 
8125 #undef __FUNCT__
8126 #define __FUNCT__ "DMPlexVecRestoreClosure"
8127 /*@C
8128   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8129 
8130   Not collective
8131 
8132   Input Parameters:
8133 + dm - The DM
8134 . section - The section describing the layout in v, or NULL to use the default section
8135 . v - The local vector
8136 . point - The sieve point in the DM
8137 . csize - The number of values in the closure, or NULL
8138 - values - The array of values, which is a borrowed array and should not be freed
8139 
8140   Level: intermediate
8141 
8142 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8143 @*/
8144 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8145 {
8146   PetscInt       size = 0;
8147   PetscErrorCode ierr;
8148 
8149   PetscFunctionBegin;
8150   /* Should work without recalculating size */
8151   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8152   PetscFunctionReturn(0);
8153 }
8154 
8155 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8156 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8157 
8158 #undef __FUNCT__
8159 #define __FUNCT__ "updatePoint_private"
8160 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8161 {
8162   PetscInt        cdof;   /* The number of constraints on this point */
8163   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8164   PetscScalar    *a;
8165   PetscInt        off, cind = 0, k;
8166   PetscErrorCode  ierr;
8167 
8168   PetscFunctionBegin;
8169   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8170   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8171   a    = &array[off];
8172   if (!cdof || setBC) {
8173     if (orientation >= 0) {
8174       for (k = 0; k < dof; ++k) {
8175         fuse(&a[k], values[k]);
8176       }
8177     } else {
8178       for (k = 0; k < dof; ++k) {
8179         fuse(&a[k], values[dof-k-1]);
8180       }
8181     }
8182   } else {
8183     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8184     if (orientation >= 0) {
8185       for (k = 0; k < dof; ++k) {
8186         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8187         fuse(&a[k], values[k]);
8188       }
8189     } else {
8190       for (k = 0; k < dof; ++k) {
8191         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8192         fuse(&a[k], values[dof-k-1]);
8193       }
8194     }
8195   }
8196   PetscFunctionReturn(0);
8197 }
8198 
8199 #undef __FUNCT__
8200 #define __FUNCT__ "updatePointFields_private"
8201 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8202 {
8203   PetscScalar   *a;
8204   PetscInt       numFields, off, foff, f;
8205   PetscErrorCode ierr;
8206 
8207   PetscFunctionBegin;
8208   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8209   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8210   a    = &array[off];
8211   for (f = 0, foff = 0; f < numFields; ++f) {
8212     PetscInt        fdof, fcomp, fcdof;
8213     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8214     PetscInt        cind = 0, k, c;
8215 
8216     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8217     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8218     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8219     if (!fcdof || setBC) {
8220       if (orientation >= 0) {
8221         for (k = 0; k < fdof; ++k) {
8222           fuse(&a[foff+k], values[foffs[f]+k]);
8223         }
8224       } else {
8225         for (k = fdof/fcomp-1; k >= 0; --k) {
8226           for (c = 0; c < fcomp; ++c) {
8227             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8228           }
8229         }
8230       }
8231     } else {
8232       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8233       if (orientation >= 0) {
8234         for (k = 0; k < fdof; ++k) {
8235           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8236           fuse(&a[foff+k], values[foffs[f]+k]);
8237         }
8238       } else {
8239         for (k = fdof/fcomp-1; k >= 0; --k) {
8240           for (c = 0; c < fcomp; ++c) {
8241             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8242             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8243           }
8244         }
8245       }
8246     }
8247     foff     += fdof;
8248     foffs[f] += fdof;
8249   }
8250   PetscFunctionReturn(0);
8251 }
8252 
8253 #undef __FUNCT__
8254 #define __FUNCT__ "DMPlexVecSetClosure"
8255 /*@C
8256   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8257 
8258   Not collective
8259 
8260   Input Parameters:
8261 + dm - The DM
8262 . section - The section describing the layout in v, or NULL to use the default sectionw
8263 . v - The local vector
8264 . point - The sieve point in the DM
8265 . values - The array of values, which is a borrowed array and should not be freed
8266 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8267 
8268   Level: intermediate
8269 
8270 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8271 @*/
8272 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8273 {
8274   PetscScalar   *array;
8275   PetscInt      *points = NULL;
8276   PetscInt       offsets[32];
8277   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8278   PetscErrorCode ierr;
8279 
8280   PetscFunctionBegin;
8281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8282   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8283   if (!section) {
8284     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8285   }
8286   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8287   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8288   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8289   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8290   /* Compress out points not in the section */
8291   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8292   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8293     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8294       points[q*2]   = points[p];
8295       points[q*2+1] = points[p+1];
8296       ++q;
8297     }
8298   }
8299   numPoints = q;
8300   for (p = 0; p < numPoints*2; p += 2) {
8301     PetscInt fdof;
8302 
8303     for (f = 0; f < numFields; ++f) {
8304       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8305       offsets[f+1] += fdof;
8306     }
8307   }
8308   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8309   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8310   if (numFields) {
8311     switch (mode) {
8312     case INSERT_VALUES:
8313       for (p = 0; p < numPoints*2; p += 2) {
8314         PetscInt o = points[p+1];
8315         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8316       } break;
8317     case INSERT_ALL_VALUES:
8318       for (p = 0; p < numPoints*2; p += 2) {
8319         PetscInt o = points[p+1];
8320         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8321       } break;
8322     case ADD_VALUES:
8323       for (p = 0; p < numPoints*2; p += 2) {
8324         PetscInt o = points[p+1];
8325         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8326       } break;
8327     case ADD_ALL_VALUES:
8328       for (p = 0; p < numPoints*2; p += 2) {
8329         PetscInt o = points[p+1];
8330         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8331       } break;
8332     default:
8333       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8334     }
8335   } else {
8336     switch (mode) {
8337     case INSERT_VALUES:
8338       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8339         PetscInt o = points[p+1];
8340         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8341         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8342       } break;
8343     case INSERT_ALL_VALUES:
8344       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8345         PetscInt o = points[p+1];
8346         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8347         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8348       } break;
8349     case ADD_VALUES:
8350       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8351         PetscInt o = points[p+1];
8352         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8353         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8354       } break;
8355     case ADD_ALL_VALUES:
8356       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8357         PetscInt o = points[p+1];
8358         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8359         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8360       } break;
8361     default:
8362       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8363     }
8364   }
8365   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8366   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8367   PetscFunctionReturn(0);
8368 }
8369 
8370 #undef __FUNCT__
8371 #define __FUNCT__ "DMPlexPrintMatSetValues"
8372 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8373 {
8374   PetscMPIInt    rank;
8375   PetscInt       i, j;
8376   PetscErrorCode ierr;
8377 
8378   PetscFunctionBegin;
8379   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8380   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8381   for (i = 0; i < numIndices; i++) {
8382     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8383   }
8384   for (i = 0; i < numIndices; i++) {
8385     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8386     for (j = 0; j < numIndices; j++) {
8387 #if defined(PETSC_USE_COMPLEX)
8388       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8389 #else
8390       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8391 #endif
8392     }
8393     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8394   }
8395   PetscFunctionReturn(0);
8396 }
8397 
8398 #undef __FUNCT__
8399 #define __FUNCT__ "indicesPoint_private"
8400 /* . off - The global offset of this point */
8401 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8402 {
8403   PetscInt        dof;    /* The number of unknowns on this point */
8404   PetscInt        cdof;   /* The number of constraints on this point */
8405   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8406   PetscInt        cind = 0, k;
8407   PetscErrorCode  ierr;
8408 
8409   PetscFunctionBegin;
8410   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8411   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8412   if (!cdof || setBC) {
8413     if (orientation >= 0) {
8414       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8415     } else {
8416       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8417     }
8418   } else {
8419     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8420     if (orientation >= 0) {
8421       for (k = 0; k < dof; ++k) {
8422         if ((cind < cdof) && (k == cdofs[cind])) {
8423           /* Insert check for returning constrained indices */
8424           indices[*loff+k] = -(off+k+1);
8425           ++cind;
8426         } else {
8427           indices[*loff+k] = off+k-cind;
8428         }
8429       }
8430     } else {
8431       for (k = 0; k < dof; ++k) {
8432         if ((cind < cdof) && (k == cdofs[cind])) {
8433           /* Insert check for returning constrained indices */
8434           indices[*loff+dof-k-1] = -(off+k+1);
8435           ++cind;
8436         } else {
8437           indices[*loff+dof-k-1] = off+k-cind;
8438         }
8439       }
8440     }
8441   }
8442   *loff += dof;
8443   PetscFunctionReturn(0);
8444 }
8445 
8446 #undef __FUNCT__
8447 #define __FUNCT__ "indicesPointFields_private"
8448 /* . off - The global offset of this point */
8449 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8450 {
8451   PetscInt       numFields, foff, f;
8452   PetscErrorCode ierr;
8453 
8454   PetscFunctionBegin;
8455   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8456   for (f = 0, foff = 0; f < numFields; ++f) {
8457     PetscInt        fdof, fcomp, cfdof;
8458     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8459     PetscInt        cind = 0, k, c;
8460 
8461     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8462     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8463     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8464     if (!cfdof || setBC) {
8465       if (orientation >= 0) {
8466         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8467       } else {
8468         for (k = fdof/fcomp-1; k >= 0; --k) {
8469           for (c = 0; c < fcomp; ++c) {
8470             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8471           }
8472         }
8473       }
8474     } else {
8475       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8476       if (orientation >= 0) {
8477         for (k = 0; k < fdof; ++k) {
8478           if ((cind < cfdof) && (k == fcdofs[cind])) {
8479             indices[foffs[f]+k] = -(off+foff+k+1);
8480             ++cind;
8481           } else {
8482             indices[foffs[f]+k] = off+foff+k-cind;
8483           }
8484         }
8485       } else {
8486         for (k = fdof/fcomp-1; k >= 0; --k) {
8487           for (c = 0; c < fcomp; ++c) {
8488             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8489               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8490               ++cind;
8491             } else {
8492               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8493             }
8494           }
8495         }
8496       }
8497     }
8498     foff     += fdof - cfdof;
8499     foffs[f] += fdof;
8500   }
8501   PetscFunctionReturn(0);
8502 }
8503 
8504 #undef __FUNCT__
8505 #define __FUNCT__ "DMPlexMatSetClosure"
8506 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8507 {
8508   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8509   PetscInt      *points = NULL;
8510   PetscInt      *indices;
8511   PetscInt       offsets[32];
8512   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8513   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8514   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8515   PetscErrorCode ierr;
8516 
8517   PetscFunctionBegin;
8518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8519   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8520   if (useDefault) {
8521     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8522   }
8523   if (useGlobalDefault) {
8524     if (useDefault) {
8525       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8526     } else {
8527       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8528     }
8529   }
8530   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8531   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8532   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8533   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8534   /* Compress out points not in the section */
8535   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8536   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8537     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8538       points[q*2]   = points[p];
8539       points[q*2+1] = points[p+1];
8540       ++q;
8541     }
8542   }
8543   numPoints = q;
8544   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8545     PetscInt fdof;
8546 
8547     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8548     for (f = 0; f < numFields; ++f) {
8549       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8550       offsets[f+1] += fdof;
8551     }
8552     numIndices += dof;
8553   }
8554   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8555 
8556   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8557   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8558   if (numFields) {
8559     for (p = 0; p < numPoints*2; p += 2) {
8560       PetscInt o = points[p+1];
8561       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8562       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8563     }
8564   } else {
8565     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8566       PetscInt o = points[p+1];
8567       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8568       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8569     }
8570   }
8571   if (useGlobalDefault && !useDefault) {
8572     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8573   }
8574   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8575   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8576   if (ierr) {
8577     PetscMPIInt    rank;
8578     PetscErrorCode ierr2;
8579 
8580     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8581     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8582     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8583     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8584     CHKERRQ(ierr);
8585   }
8586   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8587   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8588   PetscFunctionReturn(0);
8589 }
8590 
8591 #undef __FUNCT__
8592 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8593 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8594 {
8595   PetscSection       coordSection;
8596   Vec                coordinates;
8597   const PetscScalar *coords;
8598   const PetscInt     dim = 2;
8599   PetscInt           d, f;
8600   PetscErrorCode     ierr;
8601 
8602   PetscFunctionBegin;
8603   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8604   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8605   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8606   if (v0) {
8607     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8608   }
8609   if (J) {
8610     for (d = 0; d < dim; d++) {
8611       for (f = 0; f < dim; f++) {
8612         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8613       }
8614     }
8615     *detJ = J[0]*J[3] - J[1]*J[2];
8616 #if 0
8617     if (detJ < 0.0) {
8618       const PetscReal xLength = mesh->periodicity[0];
8619 
8620       if (xLength != 0.0) {
8621         PetscReal v0x = coords[0*dim+0];
8622 
8623         if (v0x == 0.0) v0x = v0[0] = xLength;
8624         for (f = 0; f < dim; f++) {
8625           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8626 
8627           J[0*dim+f] = 0.5*(px - v0x);
8628         }
8629       }
8630       detJ = J[0]*J[3] - J[1]*J[2];
8631     }
8632 #endif
8633     PetscLogFlops(8.0 + 3.0);
8634   }
8635   if (invJ) {
8636     const PetscReal invDet = 1.0/(*detJ);
8637 
8638     invJ[0] =  invDet*J[3];
8639     invJ[1] = -invDet*J[1];
8640     invJ[2] = -invDet*J[2];
8641     invJ[3] =  invDet*J[0];
8642     PetscLogFlops(5.0);
8643   }
8644   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8645   PetscFunctionReturn(0);
8646 }
8647 
8648 #undef __FUNCT__
8649 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8650 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8651 {
8652   PetscSection       coordSection;
8653   Vec                coordinates;
8654   const PetscScalar *coords;
8655   const PetscInt     dim = 2;
8656   PetscInt           d, f;
8657   PetscErrorCode     ierr;
8658 
8659   PetscFunctionBegin;
8660   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8661   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8662   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8663   if (v0) {
8664     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8665   }
8666   if (J) {
8667     for (d = 0; d < dim; d++) {
8668       for (f = 0; f < dim; f++) {
8669         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8670       }
8671     }
8672     *detJ = J[0]*J[3] - J[1]*J[2];
8673     PetscLogFlops(8.0 + 3.0);
8674   }
8675   if (invJ) {
8676     const PetscReal invDet = 1.0/(*detJ);
8677 
8678     invJ[0] =  invDet*J[3];
8679     invJ[1] = -invDet*J[1];
8680     invJ[2] = -invDet*J[2];
8681     invJ[3] =  invDet*J[0];
8682     PetscLogFlops(5.0);
8683   }
8684   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8685   PetscFunctionReturn(0);
8686 }
8687 
8688 #undef __FUNCT__
8689 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8690 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8691 {
8692   PetscSection       coordSection;
8693   Vec                coordinates;
8694   const PetscScalar *coords;
8695   const PetscInt     dim = 3;
8696   PetscInt           d, f;
8697   PetscErrorCode     ierr;
8698 
8699   PetscFunctionBegin;
8700   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8701   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8702   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8703   if (v0) {
8704     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8705   }
8706   if (J) {
8707     for (d = 0; d < dim; d++) {
8708       for (f = 0; f < dim; f++) {
8709         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8710       }
8711     }
8712     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8713     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8714              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8715              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8716     PetscLogFlops(18.0 + 12.0);
8717   }
8718   if (invJ) {
8719     const PetscReal invDet = 1.0/(*detJ);
8720 
8721     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8722     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8723     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8724     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8725     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8726     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8727     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8728     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8729     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8730     PetscLogFlops(37.0);
8731   }
8732   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8733   PetscFunctionReturn(0);
8734 }
8735 
8736 #undef __FUNCT__
8737 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8738 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8739 {
8740   PetscSection       coordSection;
8741   Vec                coordinates;
8742   const PetscScalar *coords;
8743   const PetscInt     dim = 3;
8744   PetscInt           d;
8745   PetscErrorCode     ierr;
8746 
8747   PetscFunctionBegin;
8748   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8749   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8750   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8751   if (v0) {
8752     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8753   }
8754   if (J) {
8755     for (d = 0; d < dim; d++) {
8756       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8757       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8758       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8759     }
8760     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8761              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8762              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8763     PetscLogFlops(18.0 + 12.0);
8764   }
8765   if (invJ) {
8766     const PetscReal invDet = -1.0/(*detJ);
8767 
8768     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8769     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8770     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8771     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8772     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8773     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8774     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8775     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8776     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8777     PetscLogFlops(37.0);
8778   }
8779   *detJ *= 8.0;
8780   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8781   PetscFunctionReturn(0);
8782 }
8783 
8784 #undef __FUNCT__
8785 #define __FUNCT__ "DMPlexComputeCellGeometry"
8786 /*@C
8787   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8788 
8789   Collective on DM
8790 
8791   Input Arguments:
8792 + dm   - the DM
8793 - cell - the cell
8794 
8795   Output Arguments:
8796 + v0   - the translation part of this affine transform
8797 . J    - the Jacobian of the transform to the reference element
8798 . invJ - the inverse of the Jacobian
8799 - detJ - the Jacobian determinant
8800 
8801   Level: advanced
8802 
8803 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8804 @*/
8805 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8806 {
8807   PetscInt       dim, coneSize;
8808   PetscErrorCode ierr;
8809 
8810   PetscFunctionBegin;
8811   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8812   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8813   switch (dim) {
8814   case 2:
8815     switch (coneSize) {
8816     case 3:
8817       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8818       break;
8819     case 4:
8820       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8821       break;
8822     default:
8823       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8824     }
8825     break;
8826   case 3:
8827     switch (coneSize) {
8828     case 4:
8829       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8830       break;
8831     case 8:
8832       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8833       break;
8834     default:
8835       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8836     }
8837     break;
8838   default:
8839     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8840   }
8841   PetscFunctionReturn(0);
8842 }
8843 
8844 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8845 {
8846   switch (i) {
8847   case 0:
8848     switch (j) {
8849     case 0: return 0;
8850     case 1:
8851       switch (k) {
8852       case 0: return 0;
8853       case 1: return 0;
8854       case 2: return 1;
8855       }
8856     case 2:
8857       switch (k) {
8858       case 0: return 0;
8859       case 1: return -1;
8860       case 2: return 0;
8861       }
8862     }
8863   case 1:
8864     switch (j) {
8865     case 0:
8866       switch (k) {
8867       case 0: return 0;
8868       case 1: return 0;
8869       case 2: return -1;
8870       }
8871     case 1: return 0;
8872     case 2:
8873       switch (k) {
8874       case 0: return 1;
8875       case 1: return 0;
8876       case 2: return 0;
8877       }
8878     }
8879   case 2:
8880     switch (j) {
8881     case 0:
8882       switch (k) {
8883       case 0: return 0;
8884       case 1: return 1;
8885       case 2: return 0;
8886       }
8887     case 1:
8888       switch (k) {
8889       case 0: return -1;
8890       case 1: return 0;
8891       case 2: return 0;
8892       }
8893     case 2: return 0;
8894     }
8895   }
8896   return 0;
8897 }
8898 
8899 #undef __FUNCT__
8900 #define __FUNCT__ "DMPlexCreateRigidBody"
8901 /*@C
8902   DMPlexCreateRigidBody - create rigid body modes from coordinates
8903 
8904   Collective on DM
8905 
8906   Input Arguments:
8907 + dm - the DM
8908 . section - the local section associated with the rigid field, or NULL for the default section
8909 - globalSection - the global section associated with the rigid field, or NULL for the default section
8910 
8911   Output Argument:
8912 . sp - the null space
8913 
8914   Note: This is necessary to take account of Dirichlet conditions on the displacements
8915 
8916   Level: advanced
8917 
8918 .seealso: MatNullSpaceCreate()
8919 @*/
8920 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8921 {
8922   MPI_Comm       comm;
8923   Vec            coordinates, localMode, mode[6];
8924   PetscSection   coordSection;
8925   PetscScalar   *coords;
8926   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8927   PetscErrorCode ierr;
8928 
8929   PetscFunctionBegin;
8930   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8931   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8932   if (dim == 1) {
8933     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8934     PetscFunctionReturn(0);
8935   }
8936   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8937   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8938   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8939   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8940   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8941   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8942   m    = (dim*(dim+1))/2;
8943   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8944   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8945   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8946   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8947   /* Assume P1 */
8948   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8949   for (d = 0; d < dim; ++d) {
8950     PetscScalar values[3] = {0.0, 0.0, 0.0};
8951 
8952     values[d] = 1.0;
8953     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8954     for (v = vStart; v < vEnd; ++v) {
8955       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8956     }
8957     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8958     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8959   }
8960   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8961   for (d = dim; d < dim*(dim+1)/2; ++d) {
8962     PetscInt i, j, k = dim > 2 ? d - dim : d;
8963 
8964     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8965     for (v = vStart; v < vEnd; ++v) {
8966       PetscScalar values[3] = {0.0, 0.0, 0.0};
8967       PetscInt    off;
8968 
8969       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8970       for (i = 0; i < dim; ++i) {
8971         for (j = 0; j < dim; ++j) {
8972           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8973         }
8974       }
8975       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8976     }
8977     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8978     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8979   }
8980   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8981   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8982   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8983   /* Orthonormalize system */
8984   for (i = dim; i < m; ++i) {
8985     PetscScalar dots[6];
8986 
8987     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8988     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8989     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8990     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
8991   }
8992   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8993   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8994   PetscFunctionReturn(0);
8995 }
8996 
8997 #undef __FUNCT__
8998 #define __FUNCT__ "DMPlexGetHybridBounds"
8999 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9000 {
9001   DM_Plex       *mesh = (DM_Plex*) dm->data;
9002   PetscInt       dim;
9003   PetscErrorCode ierr;
9004 
9005   PetscFunctionBegin;
9006   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9007   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9008   if (cMax) *cMax = mesh->hybridPointMax[dim];
9009   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9010   if (eMax) *eMax = mesh->hybridPointMax[1];
9011   if (vMax) *vMax = mesh->hybridPointMax[0];
9012   PetscFunctionReturn(0);
9013 }
9014 
9015 #undef __FUNCT__
9016 #define __FUNCT__ "DMPlexSetHybridBounds"
9017 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9018 {
9019   DM_Plex       *mesh = (DM_Plex*) dm->data;
9020   PetscInt       dim;
9021   PetscErrorCode ierr;
9022 
9023   PetscFunctionBegin;
9024   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9025   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9026   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9027   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9028   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9029   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9030   PetscFunctionReturn(0);
9031 }
9032 
9033 #undef __FUNCT__
9034 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9035 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9036 {
9037   DM_Plex *mesh = (DM_Plex*) dm->data;
9038 
9039   PetscFunctionBegin;
9040   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9041   PetscValidPointer(cellHeight, 2);
9042   *cellHeight = mesh->vtkCellHeight;
9043   PetscFunctionReturn(0);
9044 }
9045 
9046 #undef __FUNCT__
9047 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9048 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9049 {
9050   DM_Plex *mesh = (DM_Plex*) dm->data;
9051 
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9054   mesh->vtkCellHeight = cellHeight;
9055   PetscFunctionReturn(0);
9056 }
9057 
9058 #undef __FUNCT__
9059 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9060 /* We can easily have a form that takes an IS instead */
9061 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9062 {
9063   PetscSection   section, globalSection;
9064   PetscInt      *numbers, p;
9065   PetscErrorCode ierr;
9066 
9067   PetscFunctionBegin;
9068   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9069   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9070   for (p = pStart; p < pEnd; ++p) {
9071     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9072   }
9073   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9074   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9075   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9076   for (p = pStart; p < pEnd; ++p) {
9077     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9078   }
9079   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9080   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9081   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9082   PetscFunctionReturn(0);
9083 }
9084 
9085 #undef __FUNCT__
9086 #define __FUNCT__ "DMPlexGetCellNumbering"
9087 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9088 {
9089   DM_Plex       *mesh = (DM_Plex*) dm->data;
9090   PetscInt       cellHeight, cStart, cEnd, cMax;
9091   PetscErrorCode ierr;
9092 
9093   PetscFunctionBegin;
9094   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9095   if (!mesh->globalCellNumbers) {
9096     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9097     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9098     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9099     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9100     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9101   }
9102   *globalCellNumbers = mesh->globalCellNumbers;
9103   PetscFunctionReturn(0);
9104 }
9105 
9106 #undef __FUNCT__
9107 #define __FUNCT__ "DMPlexGetVertexNumbering"
9108 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9109 {
9110   DM_Plex       *mesh = (DM_Plex*) dm->data;
9111   PetscInt       vStart, vEnd, vMax;
9112   PetscErrorCode ierr;
9113 
9114   PetscFunctionBegin;
9115   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9116   if (!mesh->globalVertexNumbers) {
9117     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9118     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9119     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9120     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9121   }
9122   *globalVertexNumbers = mesh->globalVertexNumbers;
9123   PetscFunctionReturn(0);
9124 }
9125 
9126 #undef __FUNCT__
9127 #define __FUNCT__ "DMPlexGetScale"
9128 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9129 {
9130   DM_Plex *mesh = (DM_Plex*) dm->data;
9131 
9132   PetscFunctionBegin;
9133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9134   PetscValidPointer(scale, 3);
9135   *scale = mesh->scale[unit];
9136   PetscFunctionReturn(0);
9137 }
9138 
9139 #undef __FUNCT__
9140 #define __FUNCT__ "DMPlexSetScale"
9141 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9142 {
9143   DM_Plex *mesh = (DM_Plex*) dm->data;
9144 
9145   PetscFunctionBegin;
9146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9147   mesh->scale[unit] = scale;
9148   PetscFunctionReturn(0);
9149 }
9150 
9151 
9152 /*******************************************************************************
9153 This should be in a separate Discretization object, but I am not sure how to lay
9154 it out yet, so I am stuffing things here while I experiment.
9155 *******************************************************************************/
9156 #undef __FUNCT__
9157 #define __FUNCT__ "DMPlexSetFEMIntegration"
9158 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9159                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9160                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9161                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9162                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9163                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9164                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9165                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9166                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9167                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9168                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9169                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9170                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9171                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9172                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9173                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9174                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9175 {
9176   DM_Plex *mesh = (DM_Plex*) dm->data;
9177 
9178   PetscFunctionBegin;
9179   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9180   mesh->integrateResidualFEM       = integrateResidualFEM;
9181   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9182   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9183   PetscFunctionReturn(0);
9184 }
9185 
9186 #undef __FUNCT__
9187 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9188 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9189 {
9190   Vec            coordinates;
9191   PetscSection   section, cSection;
9192   PetscInt       dim, vStart, vEnd, v, c, d;
9193   PetscScalar   *values, *cArray;
9194   PetscReal     *coords;
9195   PetscErrorCode ierr;
9196 
9197   PetscFunctionBegin;
9198   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9199   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9200   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9201   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9202   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9203   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9204   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9205   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9206   for (v = vStart; v < vEnd; ++v) {
9207     PetscInt dof, off;
9208 
9209     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9210     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9211     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9212     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9213     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9214     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9215   }
9216   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9217   /* Temporary, must be replaced by a projection on the finite element basis */
9218   {
9219     PetscInt eStart = 0, eEnd = 0, e, depth;
9220 
9221     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9222     --depth;
9223     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9224     for (e = eStart; e < eEnd; ++e) {
9225       const PetscInt *cone = NULL;
9226       PetscInt        coneSize, d;
9227       PetscScalar    *coordsA, *coordsB;
9228 
9229       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9230       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9231       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9232       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9233       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9234       for (d = 0; d < dim; ++d) {
9235         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9236       }
9237       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9238       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9239     }
9240   }
9241 
9242   ierr = PetscFree(coords);CHKERRQ(ierr);
9243   ierr = PetscFree(values);CHKERRQ(ierr);
9244 #if 0
9245   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9246   PetscReal      detJ;
9247 
9248   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9249   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9250   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9251 
9252   for (PetscInt c = cStart; c < cEnd; ++c) {
9253     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9254     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9255     const int                          oSize   = pV.getSize();
9256     int                                v       = 0;
9257 
9258     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9259     for (PetscInt cl = 0; cl < oSize; ++cl) {
9260       const PetscInt fDim;
9261 
9262       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9263       if (pointDim) {
9264         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9265           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9266         }
9267       }
9268     }
9269     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9270     pV.clear();
9271   }
9272   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9273   ierr = PetscFree(values);CHKERRQ(ierr);
9274 #endif
9275   PetscFunctionReturn(0);
9276 }
9277 
9278 #undef __FUNCT__
9279 #define __FUNCT__ "DMPlexProjectFunction"
9280 /*@C
9281   DMPlexProjectFunction - This projects the given function into the function space provided.
9282 
9283   Input Parameters:
9284 + dm      - The DM
9285 . numComp - The number of components (functions)
9286 . funcs   - The coordinate functions to evaluate
9287 - mode    - The insertion mode for values
9288 
9289   Output Parameter:
9290 . X - vector
9291 
9292   Level: developer
9293 
9294   Note:
9295   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9296   We will eventually fix it.
9297 
9298 ,seealso: DMPlexComputeL2Diff()
9299 */
9300 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9301 {
9302   Vec            localX;
9303   PetscErrorCode ierr;
9304 
9305   PetscFunctionBegin;
9306   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9307   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9308   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9309   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9310   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9311   PetscFunctionReturn(0);
9312 }
9313 
9314 #undef __FUNCT__
9315 #define __FUNCT__ "DMPlexComputeL2Diff"
9316 /*@C
9317   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9318 
9319   Input Parameters:
9320 + dm    - The DM
9321 . quad  - The PetscQuadrature object for each field
9322 . funcs - The functions to evaluate for each field component
9323 - X     - The coefficient vector u_h
9324 
9325   Output Parameter:
9326 . diff - The diff ||u - u_h||_2
9327 
9328   Level: developer
9329 
9330 .seealso: DMPlexProjectFunction()
9331 */
9332 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9333 {
9334   const PetscInt debug = 0;
9335   PetscSection   section;
9336   Vec            localX;
9337   PetscReal     *coords, *v0, *J, *invJ, detJ;
9338   PetscReal      localDiff = 0.0;
9339   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9340   PetscErrorCode ierr;
9341 
9342   PetscFunctionBegin;
9343   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9344   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9345   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9346   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9347   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9348   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9349   for (field = 0; field < numFields; ++field) {
9350     numComponents += quad[field].numComponents;
9351   }
9352   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9353   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9354   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9355   for (c = cStart; c < cEnd; ++c) {
9356     const PetscScalar *x;
9357     PetscReal          elemDiff = 0.0;
9358 
9359     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9360     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9361     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9362 
9363     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9364       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9365       const PetscReal *quadPoints    = quad[field].quadPoints;
9366       const PetscReal *quadWeights   = quad[field].quadWeights;
9367       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9368       const PetscInt   numBasisComps = quad[field].numComponents;
9369       const PetscReal *basis         = quad[field].basis;
9370       PetscInt         q, d, e, fc, f;
9371 
9372       if (debug) {
9373         char title[1024];
9374         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9375         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9376       }
9377       for (q = 0; q < numQuadPoints; ++q) {
9378         for (d = 0; d < dim; d++) {
9379           coords[d] = v0[d];
9380           for (e = 0; e < dim; e++) {
9381             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9382           }
9383         }
9384         for (fc = 0; fc < numBasisComps; ++fc) {
9385           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9386           PetscReal       interpolant = 0.0;
9387           for (f = 0; f < numBasisFuncs; ++f) {
9388             const PetscInt fidx = f*numBasisComps+fc;
9389             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9390           }
9391           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9392           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9393         }
9394       }
9395       comp        += numBasisComps;
9396       fieldOffset += numBasisFuncs*numBasisComps;
9397     }
9398     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9399     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9400     localDiff += elemDiff;
9401   }
9402   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9403   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9404   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9405   *diff = PetscSqrtReal(*diff);
9406   PetscFunctionReturn(0);
9407 }
9408 
9409 #undef __FUNCT__
9410 #define __FUNCT__ "DMPlexComputeResidualFEM"
9411 /*@
9412   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9413 
9414   Input Parameters:
9415 + dm - The mesh
9416 . X  - Local input vector
9417 - user - The user context
9418 
9419   Output Parameter:
9420 . F  - Local output vector
9421 
9422   Note:
9423   The second member of the user context must be an FEMContext.
9424 
9425   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9426   like a GPU, or vectorize on a multicore machine.
9427 
9428 .seealso: DMPlexComputeJacobianActionFEM()
9429 */
9430 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9431 {
9432   DM_Plex         *mesh = (DM_Plex*) dm->data;
9433   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9434   PetscQuadrature *quad = fem->quad;
9435   PetscSection     section;
9436   PetscReal       *v0, *J, *invJ, *detJ;
9437   PetscScalar     *elemVec, *u;
9438   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9439   PetscInt         cellDof = 0, numComponents = 0;
9440   PetscErrorCode   ierr;
9441 
9442   PetscFunctionBegin;
9443   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9444   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9445   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9446   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9447   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9448   numCells = cEnd - cStart;
9449   for (field = 0; field < numFields; ++field) {
9450     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9451     numComponents += quad[field].numComponents;
9452   }
9453   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9454   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9455   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);
9456   for (c = cStart; c < cEnd; ++c) {
9457     const PetscScalar *x;
9458     PetscInt           i;
9459 
9460     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9461     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9462     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9463 
9464     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9465     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9466   }
9467   for (field = 0; field < numFields; ++field) {
9468     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9469     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9470     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9471     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9472     /* Conforming batches */
9473     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9474     PetscInt numBlocks  = 1;
9475     PetscInt batchSize  = numBlocks * blockSize;
9476     PetscInt numBatches = numBatchesTmp;
9477     PetscInt numChunks  = numCells / (numBatches*batchSize);
9478     /* Remainder */
9479     PetscInt numRemainder = numCells % (numBatches * batchSize);
9480     PetscInt offset       = numCells - numRemainder;
9481 
9482     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9483     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9484                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9485   }
9486   for (c = cStart; c < cEnd; ++c) {
9487     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9488     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9489   }
9490   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9491   if (mesh->printFEM) {
9492     PetscMPIInt rank, numProcs;
9493     PetscInt    p;
9494 
9495     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9496     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9497     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9498     for (p = 0; p < numProcs; ++p) {
9499       if (p == rank) {
9500         Vec f;
9501 
9502         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9503         ierr = VecCopy(F, f);CHKERRQ(ierr);
9504         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9505         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9506         ierr = VecDestroy(&f);CHKERRQ(ierr);
9507         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9508       }
9509       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9510     }
9511   }
9512   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9513   PetscFunctionReturn(0);
9514 }
9515 
9516 #undef __FUNCT__
9517 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9518 /*@C
9519   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9520 
9521   Input Parameters:
9522 + dm - The mesh
9523 . J  - The Jacobian shell matrix
9524 . X  - Local input vector
9525 - user - The user context
9526 
9527   Output Parameter:
9528 . F  - Local output vector
9529 
9530   Note:
9531   The second member of the user context must be an FEMContext.
9532 
9533   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9534   like a GPU, or vectorize on a multicore machine.
9535 
9536 .seealso: DMPlexComputeResidualFEM()
9537 */
9538 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9539 {
9540   DM_Plex         *mesh = (DM_Plex*) dm->data;
9541   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9542   PetscQuadrature *quad = fem->quad;
9543   PetscSection     section;
9544   JacActionCtx    *jctx;
9545   PetscReal       *v0, *J, *invJ, *detJ;
9546   PetscScalar     *elemVec, *u, *a;
9547   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9548   PetscInt         cellDof = 0;
9549   PetscErrorCode   ierr;
9550 
9551   PetscFunctionBegin;
9552   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9553   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9554   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9555   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9556   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9557   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9558   numCells = cEnd - cStart;
9559   for (field = 0; field < numFields; ++field) {
9560     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9561   }
9562   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9563   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);
9564   for (c = cStart; c < cEnd; ++c) {
9565     const PetscScalar *x;
9566     PetscInt           i;
9567 
9568     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9569     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9570     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9571     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9572     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9573     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9574     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9575     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9576   }
9577   for (field = 0; field < numFields; ++field) {
9578     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9579     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9580     /* Conforming batches */
9581     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9582     PetscInt numBlocks  = 1;
9583     PetscInt batchSize  = numBlocks * blockSize;
9584     PetscInt numBatches = numBatchesTmp;
9585     PetscInt numChunks  = numCells / (numBatches*batchSize);
9586     /* Remainder */
9587     PetscInt numRemainder = numCells % (numBatches * batchSize);
9588     PetscInt offset       = numCells - numRemainder;
9589 
9590     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);
9591     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],
9592                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9593   }
9594   for (c = cStart; c < cEnd; ++c) {
9595     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9596     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9597   }
9598   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9599   if (mesh->printFEM) {
9600     PetscMPIInt rank, numProcs;
9601     PetscInt    p;
9602 
9603     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9604     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9605     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9606     for (p = 0; p < numProcs; ++p) {
9607       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9608       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9609     }
9610   }
9611   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9612   PetscFunctionReturn(0);
9613 }
9614 
9615 #undef __FUNCT__
9616 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9617 /*@
9618   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9619 
9620   Input Parameters:
9621 + dm - The mesh
9622 . X  - Local input vector
9623 - user - The user context
9624 
9625   Output Parameter:
9626 . Jac  - Jacobian matrix
9627 
9628   Note:
9629   The second member of the user context must be an FEMContext.
9630 
9631   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9632   like a GPU, or vectorize on a multicore machine.
9633 
9634 .seealso: FormFunctionLocal()
9635 */
9636 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9637 {
9638   DM_Plex         *mesh = (DM_Plex*) dm->data;
9639   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9640   PetscQuadrature *quad = fem->quad;
9641   PetscSection     section;
9642   PetscReal       *v0, *J, *invJ, *detJ;
9643   PetscScalar     *elemMat, *u;
9644   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9645   PetscInt         cellDof = 0, numComponents = 0;
9646   PetscBool        isShell;
9647   PetscErrorCode   ierr;
9648 
9649   PetscFunctionBegin;
9650   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9651   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9652   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9653   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9654   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9655   numCells = cEnd - cStart;
9656   for (field = 0; field < numFields; ++field) {
9657     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9658     numComponents += quad[field].numComponents;
9659   }
9660   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9661   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9662   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);
9663   for (c = cStart; c < cEnd; ++c) {
9664     const PetscScalar *x;
9665     PetscInt           i;
9666 
9667     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9668     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9669     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9670 
9671     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9672     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9673   }
9674   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9675   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9676     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9677     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9678     PetscInt       fieldJ;
9679 
9680     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9681       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9682       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9683       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9684       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9685       /* Conforming batches */
9686       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9687       PetscInt numBlocks  = 1;
9688       PetscInt batchSize  = numBlocks * blockSize;
9689       PetscInt numBatches = numBatchesTmp;
9690       PetscInt numChunks  = numCells / (numBatches*batchSize);
9691       /* Remainder */
9692       PetscInt numRemainder = numCells % (numBatches * batchSize);
9693       PetscInt offset       = numCells - numRemainder;
9694 
9695       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9696       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9697                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9698     }
9699   }
9700   for (c = cStart; c < cEnd; ++c) {
9701     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9702     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9703   }
9704   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9705 
9706   /* Assemble matrix, using the 2-step process:
9707        MatAssemblyBegin(), MatAssemblyEnd(). */
9708   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9709   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9710 
9711   if (mesh->printFEM) {
9712     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9713     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9714     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9715   }
9716   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9717   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9718   if (isShell) {
9719     JacActionCtx *jctx;
9720 
9721     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9722     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9723   }
9724   *str = SAME_NONZERO_PATTERN;
9725   PetscFunctionReturn(0);
9726 }
9727 
9728 
9729 #undef __FUNCT__
9730 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9731 /*@C
9732   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9733   the local section and an SF describing the section point overlap.
9734 
9735   Input Parameters:
9736   + s - The PetscSection for the local field layout
9737   . sf - The SF describing parallel layout of the section points
9738   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9739   . label - The label specifying the points
9740   - labelValue - The label stratum specifying the points
9741 
9742   Output Parameter:
9743   . gsection - The PetscSection for the global field layout
9744 
9745   Note: This gives negative sizes and offsets to points not owned by this process
9746 
9747   Level: developer
9748 
9749 .seealso: PetscSectionCreate()
9750 @*/
9751 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9752 {
9753   PetscInt      *neg;
9754   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9755   PetscErrorCode ierr;
9756 
9757   PetscFunctionBegin;
9758   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9759   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9760   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9761   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9762   /* Mark ghost points with negative dof */
9763   for (p = pStart; p < pEnd; ++p) {
9764     PetscInt value;
9765 
9766     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9767     if (value != labelValue) continue;
9768     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9769     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9770     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9771     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9772     neg[p-pStart] = -(dof+1);
9773   }
9774   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9775   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9776   if (nroots >= 0) {
9777     if (nroots > pEnd - pStart) {
9778       PetscInt *tmpDof;
9779       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9780       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9781       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9782       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9783       for (p = pStart; p < pEnd; ++p) {
9784         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9785       }
9786       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9787     } else {
9788       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9789       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9790     }
9791   }
9792   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9793   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9794     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9795 
9796     (*gsection)->atlasOff[p] = off;
9797 
9798     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9799   }
9800   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9801   globalOff -= off;
9802   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9803     (*gsection)->atlasOff[p] += globalOff;
9804 
9805     neg[p] = -((*gsection)->atlasOff[p]+1);
9806   }
9807   /* Put in negative offsets for ghost points */
9808   if (nroots >= 0) {
9809     if (nroots > pEnd - pStart) {
9810       PetscInt *tmpOff;
9811       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9812       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9813       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9814       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9815       for (p = pStart; p < pEnd; ++p) {
9816         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9817       }
9818       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9819     } else {
9820       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9821       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9822     }
9823   }
9824   ierr = PetscFree(neg);CHKERRQ(ierr);
9825   PetscFunctionReturn(0);
9826 }
9827