xref: /petsc/src/dm/impls/plex/plex.c (revision 9f074e33fb8b4d6fdad352a0506a3b1288f5220f)
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 = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
4510   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
4511     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
4512   }
4513   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4514   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4515   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4516   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4517   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4518   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4519   for (v = 0; v < numPoints[0]; ++v) {
4520     PetscInt off;
4521 
4522     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
4523     for (d = 0; d < dim; ++d) {
4524       coords[off+d] = vertexCoords[v*dim+d];
4525     }
4526   }
4527   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4528   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4529   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4530   PetscFunctionReturn(0);
4531 }
4532 
4533 #if defined(PETSC_HAVE_TRIANGLE)
4534 #include <triangle.h>
4535 
4536 #undef __FUNCT__
4537 #define __FUNCT__ "InitInput_Triangle"
4538 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4539 {
4540   PetscFunctionBegin;
4541   inputCtx->numberofpoints             = 0;
4542   inputCtx->numberofpointattributes    = 0;
4543   inputCtx->pointlist                  = NULL;
4544   inputCtx->pointattributelist         = NULL;
4545   inputCtx->pointmarkerlist            = NULL;
4546   inputCtx->numberofsegments           = 0;
4547   inputCtx->segmentlist                = NULL;
4548   inputCtx->segmentmarkerlist          = NULL;
4549   inputCtx->numberoftriangleattributes = 0;
4550   inputCtx->trianglelist               = NULL;
4551   inputCtx->numberofholes              = 0;
4552   inputCtx->holelist                   = NULL;
4553   inputCtx->numberofregions            = 0;
4554   inputCtx->regionlist                 = NULL;
4555   PetscFunctionReturn(0);
4556 }
4557 
4558 #undef __FUNCT__
4559 #define __FUNCT__ "InitOutput_Triangle"
4560 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4561 {
4562   PetscFunctionBegin;
4563   outputCtx->numberofpoints        = 0;
4564   outputCtx->pointlist             = NULL;
4565   outputCtx->pointattributelist    = NULL;
4566   outputCtx->pointmarkerlist       = NULL;
4567   outputCtx->numberoftriangles     = 0;
4568   outputCtx->trianglelist          = NULL;
4569   outputCtx->triangleattributelist = NULL;
4570   outputCtx->neighborlist          = NULL;
4571   outputCtx->segmentlist           = NULL;
4572   outputCtx->segmentmarkerlist     = NULL;
4573   outputCtx->numberofedges         = 0;
4574   outputCtx->edgelist              = NULL;
4575   outputCtx->edgemarkerlist        = NULL;
4576   PetscFunctionReturn(0);
4577 }
4578 
4579 #undef __FUNCT__
4580 #define __FUNCT__ "FiniOutput_Triangle"
4581 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4582 {
4583   PetscFunctionBegin;
4584   free(outputCtx->pointmarkerlist);
4585   free(outputCtx->edgelist);
4586   free(outputCtx->edgemarkerlist);
4587   free(outputCtx->trianglelist);
4588   free(outputCtx->neighborlist);
4589   PetscFunctionReturn(0);
4590 }
4591 
4592 #undef __FUNCT__
4593 #define __FUNCT__ "DMPlexGenerate_Triangle"
4594 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4595 {
4596   MPI_Comm             comm;
4597   PetscInt             dim              = 2;
4598   const PetscBool      createConvexHull = PETSC_FALSE;
4599   const PetscBool      constrained      = PETSC_FALSE;
4600   struct triangulateio in;
4601   struct triangulateio out;
4602   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4603   PetscMPIInt          rank;
4604   PetscErrorCode       ierr;
4605 
4606   PetscFunctionBegin;
4607   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4608   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4609   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4610   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4611   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4612 
4613   in.numberofpoints = vEnd - vStart;
4614   if (in.numberofpoints > 0) {
4615     PetscSection coordSection;
4616     Vec          coordinates;
4617     PetscScalar *array;
4618 
4619     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4620     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4621     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4622     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4623     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4624     for (v = vStart; v < vEnd; ++v) {
4625       const PetscInt idx = v - vStart;
4626       PetscInt       off, d;
4627 
4628       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4629       for (d = 0; d < dim; ++d) {
4630         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4631       }
4632       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4633     }
4634     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4635   }
4636   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4637   in.numberofsegments = eEnd - eStart;
4638   if (in.numberofsegments > 0) {
4639     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4640     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4641     for (e = eStart; e < eEnd; ++e) {
4642       const PetscInt  idx = e - eStart;
4643       const PetscInt *cone;
4644 
4645       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4646 
4647       in.segmentlist[idx*2+0] = cone[0] - vStart;
4648       in.segmentlist[idx*2+1] = cone[1] - vStart;
4649 
4650       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4651     }
4652   }
4653 #if 0 /* Do not currently support holes */
4654   PetscReal *holeCoords;
4655   PetscInt   h, d;
4656 
4657   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4658   if (in.numberofholes > 0) {
4659     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4660     for (h = 0; h < in.numberofholes; ++h) {
4661       for (d = 0; d < dim; ++d) {
4662         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4663       }
4664     }
4665   }
4666 #endif
4667   if (!rank) {
4668     char args[32];
4669 
4670     /* Take away 'Q' for verbose output */
4671     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4672     if (createConvexHull) {
4673       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4674     }
4675     if (constrained) {
4676       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4677     }
4678     triangulate(args, &in, &out, NULL);
4679   }
4680   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4681   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4682   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4683   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4684   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4685 
4686   {
4687     const PetscInt numCorners  = 3;
4688     const PetscInt numCells    = out.numberoftriangles;
4689     const PetscInt numVertices = out.numberofpoints;
4690     const int     *cells      = out.trianglelist;
4691     const double  *meshCoords = out.pointlist;
4692 
4693     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4694     /* Set labels */
4695     for (v = 0; v < numVertices; ++v) {
4696       if (out.pointmarkerlist[v]) {
4697         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4698       }
4699     }
4700     if (interpolate) {
4701       for (e = 0; e < out.numberofedges; e++) {
4702         if (out.edgemarkerlist[e]) {
4703           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4704           const PetscInt *edges;
4705           PetscInt        numEdges;
4706 
4707           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4708           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4709           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4710           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4711         }
4712       }
4713     }
4714     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4715   }
4716 #if 0 /* Do not currently support holes */
4717   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4718 #endif
4719   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4720   PetscFunctionReturn(0);
4721 }
4722 
4723 #undef __FUNCT__
4724 #define __FUNCT__ "DMPlexRefine_Triangle"
4725 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4726 {
4727   MPI_Comm             comm;
4728   PetscInt             dim  = 2;
4729   struct triangulateio in;
4730   struct triangulateio out;
4731   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4732   PetscMPIInt          rank;
4733   PetscErrorCode       ierr;
4734 
4735   PetscFunctionBegin;
4736   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4737   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4738   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4739   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4740   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4741   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4742   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4743 
4744   in.numberofpoints = vEnd - vStart;
4745   if (in.numberofpoints > 0) {
4746     PetscSection coordSection;
4747     Vec          coordinates;
4748     PetscScalar *array;
4749 
4750     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4751     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4752     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4753     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4754     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4755     for (v = vStart; v < vEnd; ++v) {
4756       const PetscInt idx = v - vStart;
4757       PetscInt       off, d;
4758 
4759       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4760       for (d = 0; d < dim; ++d) {
4761         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4762       }
4763       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4764     }
4765     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4766   }
4767   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4768 
4769   in.numberofcorners   = 3;
4770   in.numberoftriangles = cEnd - cStart;
4771 
4772   in.trianglearealist  = (double*) maxVolumes;
4773   if (in.numberoftriangles > 0) {
4774     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4775     for (c = cStart; c < cEnd; ++c) {
4776       const PetscInt idx      = c - cStart;
4777       PetscInt      *closure = NULL;
4778       PetscInt       closureSize;
4779 
4780       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4781       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4782       for (v = 0; v < 3; ++v) {
4783         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4784       }
4785       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4786     }
4787   }
4788   /* TODO: Segment markers are missing on input */
4789 #if 0 /* Do not currently support holes */
4790   PetscReal *holeCoords;
4791   PetscInt   h, d;
4792 
4793   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4794   if (in.numberofholes > 0) {
4795     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4796     for (h = 0; h < in.numberofholes; ++h) {
4797       for (d = 0; d < dim; ++d) {
4798         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4799       }
4800     }
4801   }
4802 #endif
4803   if (!rank) {
4804     char args[32];
4805 
4806     /* Take away 'Q' for verbose output */
4807     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4808     triangulate(args, &in, &out, NULL);
4809   }
4810   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4811   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4812   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4813   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4814   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4815 
4816   {
4817     const PetscInt numCorners  = 3;
4818     const PetscInt numCells    = out.numberoftriangles;
4819     const PetscInt numVertices = out.numberofpoints;
4820     const int     *cells      = out.trianglelist;
4821     const double  *meshCoords = out.pointlist;
4822     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4823 
4824     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4825     /* Set labels */
4826     for (v = 0; v < numVertices; ++v) {
4827       if (out.pointmarkerlist[v]) {
4828         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4829       }
4830     }
4831     if (interpolate) {
4832       PetscInt e;
4833 
4834       for (e = 0; e < out.numberofedges; e++) {
4835         if (out.edgemarkerlist[e]) {
4836           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4837           const PetscInt *edges;
4838           PetscInt        numEdges;
4839 
4840           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4841           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4842           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4843           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4844         }
4845       }
4846     }
4847     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4848   }
4849 #if 0 /* Do not currently support holes */
4850   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4851 #endif
4852   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4853   PetscFunctionReturn(0);
4854 }
4855 #endif
4856 
4857 #if defined(PETSC_HAVE_TETGEN)
4858 #include <tetgen.h>
4859 #undef __FUNCT__
4860 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4861 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4862 {
4863   MPI_Comm       comm;
4864   const PetscInt dim  = 3;
4865   ::tetgenio     in;
4866   ::tetgenio     out;
4867   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4868   PetscMPIInt    rank;
4869   PetscErrorCode ierr;
4870 
4871   PetscFunctionBegin;
4872   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4873   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4874   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4875   in.numberofpoints = vEnd - vStart;
4876   if (in.numberofpoints > 0) {
4877     PetscSection coordSection;
4878     Vec          coordinates;
4879     PetscScalar *array;
4880 
4881     in.pointlist       = new double[in.numberofpoints*dim];
4882     in.pointmarkerlist = new int[in.numberofpoints];
4883 
4884     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4885     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4886     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4887     for (v = vStart; v < vEnd; ++v) {
4888       const PetscInt idx = v - vStart;
4889       PetscInt       off, d;
4890 
4891       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4892       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4893       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4894     }
4895     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4896   }
4897   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4898 
4899   in.numberoffacets = fEnd - fStart;
4900   if (in.numberoffacets > 0) {
4901     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4902     in.facetmarkerlist = new int[in.numberoffacets];
4903     for (f = fStart; f < fEnd; ++f) {
4904       const PetscInt idx     = f - fStart;
4905       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4906 
4907       in.facetlist[idx].numberofpolygons = 1;
4908       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4909       in.facetlist[idx].numberofholes    = 0;
4910       in.facetlist[idx].holelist         = NULL;
4911 
4912       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4913       for (p = 0; p < numPoints*2; p += 2) {
4914         const PetscInt point = points[p];
4915         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4916       }
4917 
4918       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4919       poly->numberofvertices = numVertices;
4920       poly->vertexlist       = new int[poly->numberofvertices];
4921       for (v = 0; v < numVertices; ++v) {
4922         const PetscInt vIdx = points[v] - vStart;
4923         poly->vertexlist[v] = vIdx;
4924       }
4925       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4926       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4927     }
4928   }
4929   if (!rank) {
4930     char args[32];
4931 
4932     /* Take away 'Q' for verbose output */
4933     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4934     ::tetrahedralize(args, &in, &out);
4935   }
4936   {
4937     const PetscInt numCorners  = 4;
4938     const PetscInt numCells    = out.numberoftetrahedra;
4939     const PetscInt numVertices = out.numberofpoints;
4940     const int     *cells      = out.tetrahedronlist;
4941     const double  *meshCoords = out.pointlist;
4942 
4943     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4944     /* Set labels */
4945     for (v = 0; v < numVertices; ++v) {
4946       if (out.pointmarkerlist[v]) {
4947         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4948       }
4949     }
4950     if (interpolate) {
4951       PetscInt e;
4952 
4953       for (e = 0; e < out.numberofedges; e++) {
4954         if (out.edgemarkerlist[e]) {
4955           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4956           const PetscInt *edges;
4957           PetscInt        numEdges;
4958 
4959           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4960           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4961           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4962           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4963         }
4964       }
4965       for (f = 0; f < out.numberoftrifaces; f++) {
4966         if (out.trifacemarkerlist[f]) {
4967           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4968           const PetscInt *faces;
4969           PetscInt        numFaces;
4970 
4971           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4972           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4973           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4974           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4975         }
4976       }
4977     }
4978     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4979   }
4980   PetscFunctionReturn(0);
4981 }
4982 
4983 #undef __FUNCT__
4984 #define __FUNCT__ "DMPlexRefine_Tetgen"
4985 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4986 {
4987   MPI_Comm       comm;
4988   const PetscInt dim  = 3;
4989   ::tetgenio     in;
4990   ::tetgenio     out;
4991   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4992   PetscMPIInt    rank;
4993   PetscErrorCode ierr;
4994 
4995   PetscFunctionBegin;
4996   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4997   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4998   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4999   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5000   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5001 
5002   in.numberofpoints = vEnd - vStart;
5003   if (in.numberofpoints > 0) {
5004     PetscSection coordSection;
5005     Vec          coordinates;
5006     PetscScalar *array;
5007 
5008     in.pointlist       = new double[in.numberofpoints*dim];
5009     in.pointmarkerlist = new int[in.numberofpoints];
5010 
5011     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5012     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5013     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5014     for (v = vStart; v < vEnd; ++v) {
5015       const PetscInt idx = v - vStart;
5016       PetscInt       off, d;
5017 
5018       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5019       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5020       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5021     }
5022     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5023   }
5024   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5025 
5026   in.numberofcorners       = 4;
5027   in.numberoftetrahedra    = cEnd - cStart;
5028   in.tetrahedronvolumelist = (double*) maxVolumes;
5029   if (in.numberoftetrahedra > 0) {
5030     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5031     for (c = cStart; c < cEnd; ++c) {
5032       const PetscInt idx      = c - cStart;
5033       PetscInt      *closure = NULL;
5034       PetscInt       closureSize;
5035 
5036       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5037       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5038       for (v = 0; v < 4; ++v) {
5039         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5040       }
5041       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5042     }
5043   }
5044   /* TODO: Put in boundary faces with markers */
5045   if (!rank) {
5046     char args[32];
5047 
5048     /* Take away 'Q' for verbose output */
5049     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5050     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5051     ::tetrahedralize(args, &in, &out);
5052   }
5053   in.tetrahedronvolumelist = NULL;
5054 
5055   {
5056     const PetscInt numCorners  = 4;
5057     const PetscInt numCells    = out.numberoftetrahedra;
5058     const PetscInt numVertices = out.numberofpoints;
5059     const int     *cells      = out.tetrahedronlist;
5060     const double  *meshCoords = out.pointlist;
5061     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5062 
5063     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5064     /* Set labels */
5065     for (v = 0; v < numVertices; ++v) {
5066       if (out.pointmarkerlist[v]) {
5067         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5068       }
5069     }
5070     if (interpolate) {
5071       PetscInt e, f;
5072 
5073       for (e = 0; e < out.numberofedges; e++) {
5074         if (out.edgemarkerlist[e]) {
5075           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5076           const PetscInt *edges;
5077           PetscInt        numEdges;
5078 
5079           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5080           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5081           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5082           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5083         }
5084       }
5085       for (f = 0; f < out.numberoftrifaces; f++) {
5086         if (out.trifacemarkerlist[f]) {
5087           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5088           const PetscInt *faces;
5089           PetscInt        numFaces;
5090 
5091           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5092           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5093           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5094           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5095         }
5096       }
5097     }
5098     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5099   }
5100   PetscFunctionReturn(0);
5101 }
5102 #endif
5103 
5104 #if defined(PETSC_HAVE_CTETGEN)
5105 #include "ctetgen.h"
5106 
5107 #undef __FUNCT__
5108 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5109 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5110 {
5111   MPI_Comm       comm;
5112   const PetscInt dim  = 3;
5113   PLC           *in, *out;
5114   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5115   PetscMPIInt    rank;
5116   PetscErrorCode ierr;
5117 
5118   PetscFunctionBegin;
5119   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5120   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5122   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5123   ierr = PLCCreate(&in);CHKERRQ(ierr);
5124   ierr = PLCCreate(&out);CHKERRQ(ierr);
5125 
5126   in->numberofpoints = vEnd - vStart;
5127   if (in->numberofpoints > 0) {
5128     PetscSection coordSection;
5129     Vec          coordinates;
5130     PetscScalar *array;
5131 
5132     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5133     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5134     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5135     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5136     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5137     for (v = vStart; v < vEnd; ++v) {
5138       const PetscInt idx = v - vStart;
5139       PetscInt       off, d, m;
5140 
5141       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5142       for (d = 0; d < dim; ++d) {
5143         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5144       }
5145       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5146 
5147       in->pointmarkerlist[idx] = (int) m;
5148     }
5149     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5150   }
5151   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5152 
5153   in->numberoffacets = fEnd - fStart;
5154   if (in->numberoffacets > 0) {
5155     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5156     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5157     for (f = fStart; f < fEnd; ++f) {
5158       const PetscInt idx     = f - fStart;
5159       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5160       polygon       *poly;
5161 
5162       in->facetlist[idx].numberofpolygons = 1;
5163 
5164       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5165 
5166       in->facetlist[idx].numberofholes    = 0;
5167       in->facetlist[idx].holelist         = NULL;
5168 
5169       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5170       for (p = 0; p < numPoints*2; p += 2) {
5171         const PetscInt point = points[p];
5172         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5173       }
5174 
5175       poly                   = in->facetlist[idx].polygonlist;
5176       poly->numberofvertices = numVertices;
5177       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5178       for (v = 0; v < numVertices; ++v) {
5179         const PetscInt vIdx = points[v] - vStart;
5180         poly->vertexlist[v] = vIdx;
5181       }
5182       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5183       in->facetmarkerlist[idx] = (int) m;
5184       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5185     }
5186   }
5187   if (!rank) {
5188     TetGenOpts t;
5189 
5190     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5191     t.in        = boundary; /* Should go away */
5192     t.plc       = 1;
5193     t.quality   = 1;
5194     t.edgesout  = 1;
5195     t.zeroindex = 1;
5196     t.quiet     = 1;
5197     t.verbose   = verbose;
5198     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5199     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5200   }
5201   {
5202     const PetscInt numCorners  = 4;
5203     const PetscInt numCells    = out->numberoftetrahedra;
5204     const PetscInt numVertices = out->numberofpoints;
5205     const int     *cells      = out->tetrahedronlist;
5206     const double  *meshCoords = out->pointlist;
5207 
5208     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5209     /* Set labels */
5210     for (v = 0; v < numVertices; ++v) {
5211       if (out->pointmarkerlist[v]) {
5212         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5213       }
5214     }
5215     if (interpolate) {
5216       PetscInt e;
5217 
5218       for (e = 0; e < out->numberofedges; e++) {
5219         if (out->edgemarkerlist[e]) {
5220           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5221           const PetscInt *edges;
5222           PetscInt        numEdges;
5223 
5224           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5225           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5226           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5227           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5228         }
5229       }
5230       for (f = 0; f < out->numberoftrifaces; f++) {
5231         if (out->trifacemarkerlist[f]) {
5232           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5233           const PetscInt *faces;
5234           PetscInt        numFaces;
5235 
5236           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5237           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5238           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5239           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5240         }
5241       }
5242     }
5243     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5244   }
5245 
5246   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5247   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5248   PetscFunctionReturn(0);
5249 }
5250 
5251 #undef __FUNCT__
5252 #define __FUNCT__ "DMPlexRefine_CTetgen"
5253 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5254 {
5255   MPI_Comm       comm;
5256   const PetscInt dim  = 3;
5257   PLC           *in, *out;
5258   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5259   PetscMPIInt    rank;
5260   PetscErrorCode ierr;
5261 
5262   PetscFunctionBegin;
5263   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5264   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5265   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5266   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5267   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5268   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5269   ierr = PLCCreate(&in);CHKERRQ(ierr);
5270   ierr = PLCCreate(&out);CHKERRQ(ierr);
5271 
5272   in->numberofpoints = vEnd - vStart;
5273   if (in->numberofpoints > 0) {
5274     PetscSection coordSection;
5275     Vec          coordinates;
5276     PetscScalar *array;
5277 
5278     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5279     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5280     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5281     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5282     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5283     for (v = vStart; v < vEnd; ++v) {
5284       const PetscInt idx = v - vStart;
5285       PetscInt       off, d, m;
5286 
5287       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5288       for (d = 0; d < dim; ++d) {
5289         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5290       }
5291       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5292 
5293       in->pointmarkerlist[idx] = (int) m;
5294     }
5295     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5296   }
5297   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5298 
5299   in->numberofcorners       = 4;
5300   in->numberoftetrahedra    = cEnd - cStart;
5301   in->tetrahedronvolumelist = maxVolumes;
5302   if (in->numberoftetrahedra > 0) {
5303     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5304     for (c = cStart; c < cEnd; ++c) {
5305       const PetscInt idx      = c - cStart;
5306       PetscInt      *closure = NULL;
5307       PetscInt       closureSize;
5308 
5309       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5310       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5311       for (v = 0; v < 4; ++v) {
5312         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5313       }
5314       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5315     }
5316   }
5317   if (!rank) {
5318     TetGenOpts t;
5319 
5320     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5321 
5322     t.in        = dm; /* Should go away */
5323     t.refine    = 1;
5324     t.varvolume = 1;
5325     t.quality   = 1;
5326     t.edgesout  = 1;
5327     t.zeroindex = 1;
5328     t.quiet     = 1;
5329     t.verbose   = verbose; /* Change this */
5330 
5331     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5332     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5333   }
5334   {
5335     const PetscInt numCorners  = 4;
5336     const PetscInt numCells    = out->numberoftetrahedra;
5337     const PetscInt numVertices = out->numberofpoints;
5338     const int     *cells       = out->tetrahedronlist;
5339     const double  *meshCoords  = out->pointlist;
5340     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5341 
5342     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5343     /* Set labels */
5344     for (v = 0; v < numVertices; ++v) {
5345       if (out->pointmarkerlist[v]) {
5346         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5347       }
5348     }
5349     if (interpolate) {
5350       PetscInt e, f;
5351 
5352       for (e = 0; e < out->numberofedges; e++) {
5353         if (out->edgemarkerlist[e]) {
5354           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5355           const PetscInt *edges;
5356           PetscInt        numEdges;
5357 
5358           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5359           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5360           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5361           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5362         }
5363       }
5364       for (f = 0; f < out->numberoftrifaces; f++) {
5365         if (out->trifacemarkerlist[f]) {
5366           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5367           const PetscInt *faces;
5368           PetscInt        numFaces;
5369 
5370           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5371           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5372           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5373           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5374         }
5375       }
5376     }
5377     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5378   }
5379   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5380   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5381   PetscFunctionReturn(0);
5382 }
5383 #endif
5384 
5385 #undef __FUNCT__
5386 #define __FUNCT__ "DMPlexGenerate"
5387 /*@C
5388   DMPlexGenerate - Generates a mesh.
5389 
5390   Not Collective
5391 
5392   Input Parameters:
5393 + boundary - The DMPlex boundary object
5394 . name - The mesh generation package name
5395 - interpolate - Flag to create intermediate mesh elements
5396 
5397   Output Parameter:
5398 . mesh - The DMPlex object
5399 
5400   Level: intermediate
5401 
5402 .keywords: mesh, elements
5403 .seealso: DMPlexCreate(), DMRefine()
5404 @*/
5405 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5406 {
5407   PetscInt       dim;
5408   char           genname[1024];
5409   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5410   PetscErrorCode ierr;
5411 
5412   PetscFunctionBegin;
5413   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5414   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5415   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5416   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5417   if (flg) name = genname;
5418   if (name) {
5419     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5420     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5421     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5422   }
5423   switch (dim) {
5424   case 1:
5425     if (!name || isTriangle) {
5426 #if defined(PETSC_HAVE_TRIANGLE)
5427       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5428 #else
5429       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5430 #endif
5431     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5432     break;
5433   case 2:
5434     if (!name || isCTetgen) {
5435 #if defined(PETSC_HAVE_CTETGEN)
5436       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5437 #else
5438       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5439 #endif
5440     } else if (isTetgen) {
5441 #if defined(PETSC_HAVE_TETGEN)
5442       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5443 #else
5444       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5445 #endif
5446     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5447     break;
5448   default:
5449     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5450   }
5451   PetscFunctionReturn(0);
5452 }
5453 
5454 typedef PetscInt CellRefiner;
5455 
5456 #undef __FUNCT__
5457 #define __FUNCT__ "GetDepthStart_Private"
5458 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5459 {
5460   PetscFunctionBegin;
5461   if (cStart) *cStart = 0;
5462   if (vStart) *vStart = depthSize[depth];
5463   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5464   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5465   PetscFunctionReturn(0);
5466 }
5467 
5468 #undef __FUNCT__
5469 #define __FUNCT__ "GetDepthEnd_Private"
5470 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5471 {
5472   PetscFunctionBegin;
5473   if (cEnd) *cEnd = depthSize[depth];
5474   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5475   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5476   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5477   PetscFunctionReturn(0);
5478 }
5479 
5480 #undef __FUNCT__
5481 #define __FUNCT__ "CellRefinerGetSizes"
5482 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5483 {
5484   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5485   PetscErrorCode ierr;
5486 
5487   PetscFunctionBegin;
5488   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5489   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5490   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5491   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5492   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5493   switch (refiner) {
5494   case 1:
5495     /* Simplicial 2D */
5496     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5497     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5498     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5499     break;
5500   case 3:
5501     /* Hybrid 2D */
5502     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5503     cMax = PetscMin(cEnd, cMax);
5504     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5505     fMax         = PetscMin(fEnd, fMax);
5506     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5507     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 */
5508     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5509     break;
5510   case 2:
5511     /* Hex 2D */
5512     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5513     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5514     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5515     break;
5516   default:
5517     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5518   }
5519   PetscFunctionReturn(0);
5520 }
5521 
5522 #undef __FUNCT__
5523 #define __FUNCT__ "CellRefinerSetConeSizes"
5524 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5525 {
5526   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5527   PetscErrorCode ierr;
5528 
5529   PetscFunctionBegin;
5530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5531   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5532   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5533   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5534   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5535   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5536   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5537   switch (refiner) {
5538   case 1:
5539     /* Simplicial 2D */
5540     /* All cells have 3 faces */
5541     for (c = cStart; c < cEnd; ++c) {
5542       for (r = 0; r < 4; ++r) {
5543         const PetscInt newp = (c - cStart)*4 + r;
5544 
5545         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5546       }
5547     }
5548     /* Split faces have 2 vertices and the same cells as the parent */
5549     for (f = fStart; f < fEnd; ++f) {
5550       for (r = 0; r < 2; ++r) {
5551         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5552         PetscInt       size;
5553 
5554         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5555         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5556         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5557       }
5558     }
5559     /* Interior faces have 2 vertices and 2 cells */
5560     for (c = cStart; c < cEnd; ++c) {
5561       for (r = 0; r < 3; ++r) {
5562         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5563 
5564         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5565         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5566       }
5567     }
5568     /* Old vertices have identical supports */
5569     for (v = vStart; v < vEnd; ++v) {
5570       const PetscInt newp = vStartNew + (v - vStart);
5571       PetscInt       size;
5572 
5573       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5574       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5575     }
5576     /* Face vertices have 2 + cells*2 supports */
5577     for (f = fStart; f < fEnd; ++f) {
5578       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5579       PetscInt       size;
5580 
5581       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5582       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5583     }
5584     break;
5585   case 2:
5586     /* Hex 2D */
5587     /* All cells have 4 faces */
5588     for (c = cStart; c < cEnd; ++c) {
5589       for (r = 0; r < 4; ++r) {
5590         const PetscInt newp = (c - cStart)*4 + r;
5591 
5592         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5593       }
5594     }
5595     /* Split faces have 2 vertices and the same cells as the parent */
5596     for (f = fStart; f < fEnd; ++f) {
5597       for (r = 0; r < 2; ++r) {
5598         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5599         PetscInt       size;
5600 
5601         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5602         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5603         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5604       }
5605     }
5606     /* Interior faces have 2 vertices and 2 cells */
5607     for (c = cStart; c < cEnd; ++c) {
5608       for (r = 0; r < 4; ++r) {
5609         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5610 
5611         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5612         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5613       }
5614     }
5615     /* Old vertices have identical supports */
5616     for (v = vStart; v < vEnd; ++v) {
5617       const PetscInt newp = vStartNew + (v - vStart);
5618       PetscInt       size;
5619 
5620       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5621       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5622     }
5623     /* Face vertices have 2 + cells supports */
5624     for (f = fStart; f < fEnd; ++f) {
5625       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5626       PetscInt       size;
5627 
5628       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5629       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5630     }
5631     /* Cell vertices have 4 supports */
5632     for (c = cStart; c < cEnd; ++c) {
5633       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5634 
5635       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5636     }
5637     break;
5638   case 3:
5639     /* Hybrid 2D */
5640     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5641     cMax = PetscMin(cEnd, cMax);
5642     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5643     fMax = PetscMin(fEnd, fMax);
5644     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5645     /* Interior cells have 3 faces */
5646     for (c = cStart; c < cMax; ++c) {
5647       for (r = 0; r < 4; ++r) {
5648         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5649 
5650         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5651       }
5652     }
5653     /* Hybrid cells have 4 faces */
5654     for (c = cMax; c < cEnd; ++c) {
5655       for (r = 0; r < 2; ++r) {
5656         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5657 
5658         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5659       }
5660     }
5661     /* Interior split faces have 2 vertices and the same cells as the parent */
5662     for (f = fStart; f < fMax; ++f) {
5663       for (r = 0; r < 2; ++r) {
5664         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5665         PetscInt       size;
5666 
5667         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5668         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5669         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5670       }
5671     }
5672     /* Interior cell faces have 2 vertices and 2 cells */
5673     for (c = cStart; c < cMax; ++c) {
5674       for (r = 0; r < 3; ++r) {
5675         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5676 
5677         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5678         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5679       }
5680     }
5681     /* Hybrid faces have 2 vertices and the same cells */
5682     for (f = fMax; f < fEnd; ++f) {
5683       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5684       PetscInt       size;
5685 
5686       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5687       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5688       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5689     }
5690     /* Hybrid cell faces have 2 vertices and 2 cells */
5691     for (c = cMax; c < cEnd; ++c) {
5692       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5693 
5694       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5695       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5696     }
5697     /* Old vertices have identical supports */
5698     for (v = vStart; v < vEnd; ++v) {
5699       const PetscInt newp = vStartNew + (v - vStart);
5700       PetscInt       size;
5701 
5702       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5703       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5704     }
5705     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5706     for (f = fStart; f < fMax; ++f) {
5707       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5708       const PetscInt *support;
5709       PetscInt       size, newSize = 2, s;
5710 
5711       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5712       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5713       for (s = 0; s < size; ++s) {
5714         if (support[s] >= cMax) newSize += 1;
5715         else newSize += 2;
5716       }
5717       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5718     }
5719     break;
5720   default:
5721     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5722   }
5723   PetscFunctionReturn(0);
5724 }
5725 
5726 #undef __FUNCT__
5727 #define __FUNCT__ "CellRefinerSetCones"
5728 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5729 {
5730   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;
5731   PetscInt       maxSupportSize, *supportRef;
5732   PetscErrorCode ierr;
5733 
5734   PetscFunctionBegin;
5735   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5736   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5737   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5738   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5739   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5740   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5741   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5742   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5743   switch (refiner) {
5744   case 1:
5745     /* Simplicial 2D */
5746     /*
5747      2
5748      |\
5749      | \
5750      |  \
5751      |   \
5752      | C  \
5753      |     \
5754      |      \
5755      2---1---1
5756      |\  D  / \
5757      | 2   0   \
5758      |A \ /  B  \
5759      0---0-------1
5760      */
5761     /* All cells have 3 faces */
5762     for (c = cStart; c < cEnd; ++c) {
5763       const PetscInt  newp = cStartNew + (c - cStart)*4;
5764       const PetscInt *cone, *ornt;
5765       PetscInt        coneNew[3], orntNew[3];
5766 
5767       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5768       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5769       /* A triangle */
5770       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5771       orntNew[0] = ornt[0];
5772       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5773       orntNew[1] = -2;
5774       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5775       orntNew[2] = ornt[2];
5776       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5777       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5778 #if 1
5779       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);
5780       for (p = 0; p < 3; ++p) {
5781         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);
5782       }
5783 #endif
5784       /* B triangle */
5785       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5786       orntNew[0] = ornt[0];
5787       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5788       orntNew[1] = ornt[1];
5789       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5790       orntNew[2] = -2;
5791       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5792       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5793 #if 1
5794       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);
5795       for (p = 0; p < 3; ++p) {
5796         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);
5797       }
5798 #endif
5799       /* C triangle */
5800       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5801       orntNew[0] = -2;
5802       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5803       orntNew[1] = ornt[1];
5804       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5805       orntNew[2] = ornt[2];
5806       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5807       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5808 #if 1
5809       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);
5810       for (p = 0; p < 3; ++p) {
5811         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);
5812       }
5813 #endif
5814       /* D triangle */
5815       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5816       orntNew[0] = 0;
5817       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5818       orntNew[1] = 0;
5819       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5820       orntNew[2] = 0;
5821       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5822       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5823 #if 1
5824       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);
5825       for (p = 0; p < 3; ++p) {
5826         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);
5827       }
5828 #endif
5829     }
5830     /* Split faces have 2 vertices and the same cells as the parent */
5831     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5832     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5833     for (f = fStart; f < fEnd; ++f) {
5834       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5835 
5836       for (r = 0; r < 2; ++r) {
5837         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5838         const PetscInt *cone, *support;
5839         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5840 
5841         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5842         coneNew[0]       = vStartNew + (cone[0] - vStart);
5843         coneNew[1]       = vStartNew + (cone[1] - vStart);
5844         coneNew[(r+1)%2] = newv;
5845         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5846 #if 1
5847         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5848         for (p = 0; p < 2; ++p) {
5849           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);
5850         }
5851 #endif
5852         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5853         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5854         for (s = 0; s < supportSize; ++s) {
5855           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5856           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5857           for (c = 0; c < coneSize; ++c) {
5858             if (cone[c] == f) break;
5859           }
5860           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5861         }
5862         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5863 #if 1
5864         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5865         for (p = 0; p < supportSize; ++p) {
5866           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);
5867         }
5868 #endif
5869       }
5870     }
5871     /* Interior faces have 2 vertices and 2 cells */
5872     for (c = cStart; c < cEnd; ++c) {
5873       const PetscInt *cone;
5874 
5875       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5876       for (r = 0; r < 3; ++r) {
5877         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5878         PetscInt       coneNew[2];
5879         PetscInt       supportNew[2];
5880 
5881         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5882         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5883         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5884 #if 1
5885         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5886         for (p = 0; p < 2; ++p) {
5887           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);
5888         }
5889 #endif
5890         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5891         supportNew[1] = (c - cStart)*4 + 3;
5892         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5893 #if 1
5894         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5895         for (p = 0; p < 2; ++p) {
5896           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);
5897         }
5898 #endif
5899       }
5900     }
5901     /* Old vertices have identical supports */
5902     for (v = vStart; v < vEnd; ++v) {
5903       const PetscInt  newp = vStartNew + (v - vStart);
5904       const PetscInt *support, *cone;
5905       PetscInt        size, s;
5906 
5907       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5908       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5909       for (s = 0; s < size; ++s) {
5910         PetscInt r = 0;
5911 
5912         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5913         if (cone[1] == v) r = 1;
5914         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5915       }
5916       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5917 #if 1
5918       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5919       for (p = 0; p < size; ++p) {
5920         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);
5921       }
5922 #endif
5923     }
5924     /* Face vertices have 2 + cells*2 supports */
5925     for (f = fStart; f < fEnd; ++f) {
5926       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5927       const PetscInt *cone, *support;
5928       PetscInt        size, s;
5929 
5930       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5931       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5932       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5933       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5934       for (s = 0; s < size; ++s) {
5935         PetscInt r = 0;
5936 
5937         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5938         if      (cone[1] == f) r = 1;
5939         else if (cone[2] == f) r = 2;
5940         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5941         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5942       }
5943       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5944 #if 1
5945       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5946       for (p = 0; p < 2+size*2; ++p) {
5947         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);
5948       }
5949 #endif
5950     }
5951     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5952     break;
5953   case 2:
5954     /* Hex 2D */
5955     /*
5956      3---------2---------2
5957      |         |         |
5958      |    D    2    C    |
5959      |         |         |
5960      3----3----0----1----1
5961      |         |         |
5962      |    A    0    B    |
5963      |         |         |
5964      0---------0---------1
5965      */
5966     /* All cells have 4 faces */
5967     for (c = cStart; c < cEnd; ++c) {
5968       const PetscInt  newp = (c - cStart)*4;
5969       const PetscInt *cone, *ornt;
5970       PetscInt        coneNew[4], orntNew[4];
5971 
5972       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5973       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5974       /* A quad */
5975       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5976       orntNew[0] = ornt[0];
5977       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5978       orntNew[1] = 0;
5979       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5980       orntNew[2] = -2;
5981       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5982       orntNew[3] = ornt[3];
5983       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5984       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5985 #if 1
5986       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);
5987       for (p = 0; p < 4; ++p) {
5988         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);
5989       }
5990 #endif
5991       /* B quad */
5992       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5993       orntNew[0] = ornt[0];
5994       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5995       orntNew[1] = ornt[1];
5996       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5997       orntNew[2] = 0;
5998       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5999       orntNew[3] = -2;
6000       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6001       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6002 #if 1
6003       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);
6004       for (p = 0; p < 4; ++p) {
6005         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);
6006       }
6007 #endif
6008       /* C quad */
6009       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6010       orntNew[0] = -2;
6011       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6012       orntNew[1] = ornt[1];
6013       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6014       orntNew[2] = ornt[2];
6015       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6016       orntNew[3] = 0;
6017       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6018       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6019 #if 1
6020       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);
6021       for (p = 0; p < 4; ++p) {
6022         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);
6023       }
6024 #endif
6025       /* D quad */
6026       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6027       orntNew[0] = 0;
6028       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6029       orntNew[1] = -2;
6030       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6031       orntNew[2] = ornt[2];
6032       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6033       orntNew[3] = ornt[3];
6034       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6035       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6036 #if 1
6037       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);
6038       for (p = 0; p < 4; ++p) {
6039         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);
6040       }
6041 #endif
6042     }
6043     /* Split faces have 2 vertices and the same cells as the parent */
6044     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6045     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6046     for (f = fStart; f < fEnd; ++f) {
6047       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6048 
6049       for (r = 0; r < 2; ++r) {
6050         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6051         const PetscInt *cone, *support;
6052         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6053 
6054         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6055         coneNew[0]       = vStartNew + (cone[0] - vStart);
6056         coneNew[1]       = vStartNew + (cone[1] - vStart);
6057         coneNew[(r+1)%2] = newv;
6058         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6059 #if 1
6060         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6061         for (p = 0; p < 2; ++p) {
6062           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);
6063         }
6064 #endif
6065         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6066         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6067         for (s = 0; s < supportSize; ++s) {
6068           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6069           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6070           for (c = 0; c < coneSize; ++c) {
6071             if (cone[c] == f) break;
6072           }
6073           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6074         }
6075         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6076 #if 1
6077         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6078         for (p = 0; p < supportSize; ++p) {
6079           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);
6080         }
6081 #endif
6082       }
6083     }
6084     /* Interior faces have 2 vertices and 2 cells */
6085     for (c = cStart; c < cEnd; ++c) {
6086       const PetscInt *cone;
6087       PetscInt        coneNew[2], supportNew[2];
6088 
6089       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6090       for (r = 0; r < 4; ++r) {
6091         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6092 
6093         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6094         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6095         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6096 #if 1
6097         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6098         for (p = 0; p < 2; ++p) {
6099           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);
6100         }
6101 #endif
6102         supportNew[0] = (c - cStart)*4 + r;
6103         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6104         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6105 #if 1
6106         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6107         for (p = 0; p < 2; ++p) {
6108           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);
6109         }
6110 #endif
6111       }
6112     }
6113     /* Old vertices have identical supports */
6114     for (v = vStart; v < vEnd; ++v) {
6115       const PetscInt  newp = vStartNew + (v - vStart);
6116       const PetscInt *support, *cone;
6117       PetscInt        size, s;
6118 
6119       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6120       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6121       for (s = 0; s < size; ++s) {
6122         PetscInt r = 0;
6123 
6124         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6125         if (cone[1] == v) r = 1;
6126         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6127       }
6128       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6129 #if 1
6130       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6131       for (p = 0; p < size; ++p) {
6132         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);
6133       }
6134 #endif
6135     }
6136     /* Face vertices have 2 + cells supports */
6137     for (f = fStart; f < fEnd; ++f) {
6138       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6139       const PetscInt *cone, *support;
6140       PetscInt        size, s;
6141 
6142       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6143       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6144       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6145       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6146       for (s = 0; s < size; ++s) {
6147         PetscInt r = 0;
6148 
6149         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6150         if      (cone[1] == f) r = 1;
6151         else if (cone[2] == f) r = 2;
6152         else if (cone[3] == f) r = 3;
6153         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6154       }
6155       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6156 #if 1
6157       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6158       for (p = 0; p < 2+size; ++p) {
6159         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);
6160       }
6161 #endif
6162     }
6163     /* Cell vertices have 4 supports */
6164     for (c = cStart; c < cEnd; ++c) {
6165       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6166       PetscInt       supportNew[4];
6167 
6168       for (r = 0; r < 4; ++r) {
6169         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6170       }
6171       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6172     }
6173     break;
6174   case 3:
6175     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6176     cMax = PetscMin(cEnd, cMax);
6177     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6178     fMax = PetscMin(fEnd, fMax);
6179     /* Interior cells have 3 faces */
6180     for (c = cStart; c < cMax; ++c) {
6181       const PetscInt  newp = cStartNew + (c - cStart)*4;
6182       const PetscInt *cone, *ornt;
6183       PetscInt        coneNew[3], orntNew[3];
6184 
6185       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6186       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6187       /* A triangle */
6188       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6189       orntNew[0] = ornt[0];
6190       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6191       orntNew[1] = -2;
6192       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6193       orntNew[2] = ornt[2];
6194       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6195       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6196 #if 1
6197       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);
6198       for (p = 0; p < 3; ++p) {
6199         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6200       }
6201 #endif
6202       /* B triangle */
6203       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6204       orntNew[0] = ornt[0];
6205       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6206       orntNew[1] = ornt[1];
6207       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6208       orntNew[2] = -2;
6209       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6210       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6211 #if 1
6212       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);
6213       for (p = 0; p < 3; ++p) {
6214         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);
6215       }
6216 #endif
6217       /* C triangle */
6218       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6219       orntNew[0] = -2;
6220       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6221       orntNew[1] = ornt[1];
6222       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6223       orntNew[2] = ornt[2];
6224       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6225       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6226 #if 1
6227       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);
6228       for (p = 0; p < 3; ++p) {
6229         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);
6230       }
6231 #endif
6232       /* D triangle */
6233       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6234       orntNew[0] = 0;
6235       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6236       orntNew[1] = 0;
6237       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6238       orntNew[2] = 0;
6239       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6240       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6241 #if 1
6242       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);
6243       for (p = 0; p < 3; ++p) {
6244         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);
6245       }
6246 #endif
6247     }
6248     /*
6249      2----3----3
6250      |         |
6251      |    B    |
6252      |         |
6253      0----4--- 1
6254      |         |
6255      |    A    |
6256      |         |
6257      0----2----1
6258      */
6259     /* Hybrid cells have 4 faces */
6260     for (c = cMax; c < cEnd; ++c) {
6261       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6262       const PetscInt *cone, *ornt;
6263       PetscInt        coneNew[4], orntNew[4];
6264 
6265       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6266       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6267       /* A quad */
6268       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6269       orntNew[0] = ornt[0];
6270       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6271       orntNew[1] = ornt[1];
6272       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6273       orntNew[2] = 0;
6274       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6275       orntNew[3] = 0;
6276       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6277       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6278 #if 1
6279       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);
6280       for (p = 0; p < 4; ++p) {
6281         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);
6282       }
6283 #endif
6284       /* B quad */
6285       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6286       orntNew[0] = ornt[0];
6287       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6288       orntNew[1] = ornt[1];
6289       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6290       orntNew[2] = 0;
6291       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6292       orntNew[3] = 0;
6293       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6294       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6295 #if 1
6296       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);
6297       for (p = 0; p < 4; ++p) {
6298         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);
6299       }
6300 #endif
6301     }
6302     /* Interior split faces have 2 vertices and the same cells as the parent */
6303     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6304     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6305     for (f = fStart; f < fMax; ++f) {
6306       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6307 
6308       for (r = 0; r < 2; ++r) {
6309         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6310         const PetscInt *cone, *support;
6311         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6312 
6313         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6314         coneNew[0]       = vStartNew + (cone[0] - vStart);
6315         coneNew[1]       = vStartNew + (cone[1] - vStart);
6316         coneNew[(r+1)%2] = newv;
6317         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6318 #if 1
6319         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6320         for (p = 0; p < 2; ++p) {
6321           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);
6322         }
6323 #endif
6324         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6325         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6326         for (s = 0; s < supportSize; ++s) {
6327           if (support[s] >= cMax) {
6328             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6329           } else {
6330             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6331             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6332             for (c = 0; c < coneSize; ++c) {
6333               if (cone[c] == f) break;
6334             }
6335             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6336           }
6337         }
6338         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6339 #if 1
6340         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6341         for (p = 0; p < supportSize; ++p) {
6342           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);
6343         }
6344 #endif
6345       }
6346     }
6347     /* Interior cell faces have 2 vertices and 2 cells */
6348     for (c = cStart; c < cMax; ++c) {
6349       const PetscInt *cone;
6350 
6351       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6352       for (r = 0; r < 3; ++r) {
6353         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6354         PetscInt       coneNew[2];
6355         PetscInt       supportNew[2];
6356 
6357         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6358         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6359         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6360 #if 1
6361         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6362         for (p = 0; p < 2; ++p) {
6363           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);
6364         }
6365 #endif
6366         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6367         supportNew[1] = (c - cStart)*4 + 3;
6368         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6369 #if 1
6370         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6371         for (p = 0; p < 2; ++p) {
6372           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);
6373         }
6374 #endif
6375       }
6376     }
6377     /* Interior hybrid faces have 2 vertices and the same cells */
6378     for (f = fMax; f < fEnd; ++f) {
6379       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6380       const PetscInt *cone;
6381       const PetscInt *support;
6382       PetscInt        coneNew[2];
6383       PetscInt        supportNew[2];
6384       PetscInt        size, s, r;
6385 
6386       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6387       coneNew[0] = vStartNew + (cone[0] - vStart);
6388       coneNew[1] = vStartNew + (cone[1] - vStart);
6389       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6390 #if 1
6391       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6392       for (p = 0; p < 2; ++p) {
6393         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);
6394       }
6395 #endif
6396       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6397       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6398       for (s = 0; s < size; ++s) {
6399         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6400         for (r = 0; r < 2; ++r) {
6401           if (cone[r+2] == f) break;
6402         }
6403         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6404       }
6405       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6406 #if 1
6407       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6408       for (p = 0; p < size; ++p) {
6409         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);
6410       }
6411 #endif
6412     }
6413     /* Cell hybrid faces have 2 vertices and 2 cells */
6414     for (c = cMax; c < cEnd; ++c) {
6415       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6416       const PetscInt *cone;
6417       PetscInt        coneNew[2];
6418       PetscInt        supportNew[2];
6419 
6420       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6421       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6422       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6423       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6424 #if 1
6425       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6426       for (p = 0; p < 2; ++p) {
6427         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);
6428       }
6429 #endif
6430       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6431       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6432       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6433 #if 1
6434       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6435       for (p = 0; p < 2; ++p) {
6436         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);
6437       }
6438 #endif
6439     }
6440     /* Old vertices have identical supports */
6441     for (v = vStart; v < vEnd; ++v) {
6442       const PetscInt  newp = vStartNew + (v - vStart);
6443       const PetscInt *support, *cone;
6444       PetscInt        size, s;
6445 
6446       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6447       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6448       for (s = 0; s < size; ++s) {
6449         if (support[s] >= fMax) {
6450           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6451         } else {
6452           PetscInt r = 0;
6453 
6454           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6455           if (cone[1] == v) r = 1;
6456           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6457         }
6458       }
6459       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6460 #if 1
6461       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6462       for (p = 0; p < size; ++p) {
6463         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);
6464       }
6465 #endif
6466     }
6467     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6468     for (f = fStart; f < fMax; ++f) {
6469       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6470       const PetscInt *cone, *support;
6471       PetscInt        size, newSize = 2, s;
6472 
6473       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6474       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6475       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6476       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6477       for (s = 0; s < size; ++s) {
6478         PetscInt r = 0;
6479 
6480         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6481         if (support[s] >= cMax) {
6482           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6483 
6484           newSize += 1;
6485         } else {
6486           if      (cone[1] == f) r = 1;
6487           else if (cone[2] == f) r = 2;
6488           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6489           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6490 
6491           newSize += 2;
6492         }
6493       }
6494       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6495 #if 1
6496       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6497       for (p = 0; p < newSize; ++p) {
6498         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);
6499       }
6500 #endif
6501     }
6502     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6503     break;
6504   default:
6505     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6506   }
6507   PetscFunctionReturn(0);
6508 }
6509 
6510 #undef __FUNCT__
6511 #define __FUNCT__ "CellRefinerSetCoordinates"
6512 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6513 {
6514   PetscSection   coordSection, coordSectionNew;
6515   Vec            coordinates, coordinatesNew;
6516   PetscScalar   *coords, *coordsNew;
6517   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6518   PetscErrorCode ierr;
6519 
6520   PetscFunctionBegin;
6521   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6522   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6523   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6524   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6525   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6526   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6527   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6528   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6529   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6530   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6531   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6532   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6533   if (fMax < 0) fMax = fEnd;
6534   switch (refiner) {
6535   case 1:
6536   case 2:
6537   case 3:
6538     /* Simplicial and Hex 2D */
6539     /* All vertices have the dim coordinates */
6540     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6541       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6542       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6543     }
6544     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6545     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6546     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6547     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6548     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6549     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6550     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6551     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6552     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6553     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6554     /* Old vertices have the same coordinates */
6555     for (v = vStart; v < vEnd; ++v) {
6556       const PetscInt newv = vStartNew + (v - vStart);
6557       PetscInt       off, offnew, d;
6558 
6559       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6560       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6561       for (d = 0; d < dim; ++d) {
6562         coordsNew[offnew+d] = coords[off+d];
6563       }
6564     }
6565     /* Face vertices have the average of endpoint coordinates */
6566     for (f = fStart; f < fMax; ++f) {
6567       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6568       const PetscInt *cone;
6569       PetscInt        coneSize, offA, offB, offnew, d;
6570 
6571       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6572       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6573       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6574       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6575       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6576       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6577       for (d = 0; d < dim; ++d) {
6578         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6579       }
6580     }
6581     /* Just Hex 2D */
6582     if (refiner == 2) {
6583       /* Cell vertices have the average of corner coordinates */
6584       for (c = cStart; c < cEnd; ++c) {
6585         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6586         PetscInt      *cone = NULL;
6587         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6588 
6589         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6590         for (p = 0; p < closureSize*2; p += 2) {
6591           const PetscInt point = cone[p];
6592           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6593         }
6594         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6595         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6596         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6597         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6598         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6599         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6600         for (d = 0; d < dim; ++d) {
6601           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6602         }
6603         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6604       }
6605     }
6606     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6607     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6608     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6609     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6610     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6611     break;
6612   default:
6613     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6614   }
6615   PetscFunctionReturn(0);
6616 }
6617 
6618 #undef __FUNCT__
6619 #define __FUNCT__ "DMPlexCreateProcessSF"
6620 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6621 {
6622   PetscInt           numRoots, numLeaves, l;
6623   const PetscInt    *localPoints;
6624   const PetscSFNode *remotePoints;
6625   PetscInt          *localPointsNew;
6626   PetscSFNode       *remotePointsNew;
6627   PetscInt          *ranks, *ranksNew;
6628   PetscErrorCode     ierr;
6629 
6630   PetscFunctionBegin;
6631   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6632   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6633   for (l = 0; l < numLeaves; ++l) {
6634     ranks[l] = remotePoints[l].rank;
6635   }
6636   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6637   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6638   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6639   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6640   for (l = 0; l < numLeaves; ++l) {
6641     ranksNew[l]              = ranks[l];
6642     localPointsNew[l]        = l;
6643     remotePointsNew[l].index = 0;
6644     remotePointsNew[l].rank  = ranksNew[l];
6645   }
6646   ierr = PetscFree(ranks);CHKERRQ(ierr);
6647   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6648   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6649   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6650   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6651   PetscFunctionReturn(0);
6652 }
6653 
6654 #undef __FUNCT__
6655 #define __FUNCT__ "CellRefinerCreateSF"
6656 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6657 {
6658   PetscSF            sf, sfNew, sfProcess;
6659   IS                 processRanks;
6660   MPI_Datatype       depthType;
6661   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6662   const PetscInt    *localPoints, *neighbors;
6663   const PetscSFNode *remotePoints;
6664   PetscInt          *localPointsNew;
6665   PetscSFNode       *remotePointsNew;
6666   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6667   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6668   PetscErrorCode     ierr;
6669 
6670   PetscFunctionBegin;
6671   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6672   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6673   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6674   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6675   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6676   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6677   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6678   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6679   switch (refiner) {
6680   case 3:
6681     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6682     cMax = PetscMin(cEnd, cMax);
6683     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6684     fMax = PetscMin(fEnd, fMax);
6685   }
6686   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6687   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6688   /* Caculate size of new SF */
6689   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6690   if (numRoots < 0) PetscFunctionReturn(0);
6691   for (l = 0; l < numLeaves; ++l) {
6692     const PetscInt p = localPoints[l];
6693 
6694     switch (refiner) {
6695     case 1:
6696       /* Simplicial 2D */
6697       if ((p >= vStart) && (p < vEnd)) {
6698         /* Old vertices stay the same */
6699         ++numLeavesNew;
6700       } else if ((p >= fStart) && (p < fEnd)) {
6701         /* Old faces add new faces and vertex */
6702         numLeavesNew += 1 + 2;
6703       } else if ((p >= cStart) && (p < cEnd)) {
6704         /* Old cells add new cells and interior faces */
6705         numLeavesNew += 4 + 3;
6706       }
6707       break;
6708     case 2:
6709       /* Hex 2D */
6710       if ((p >= vStart) && (p < vEnd)) {
6711         /* Old vertices stay the same */
6712         ++numLeavesNew;
6713       } else if ((p >= fStart) && (p < fEnd)) {
6714         /* Old faces add new faces and vertex */
6715         numLeavesNew += 1 + 2;
6716       } else if ((p >= cStart) && (p < cEnd)) {
6717         /* Old cells add new cells and interior faces */
6718         numLeavesNew += 4 + 4;
6719       }
6720       break;
6721     default:
6722       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6723     }
6724   }
6725   /* Communicate depthSizes for each remote rank */
6726   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6727   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6728   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6729   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);
6730   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6731   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6732   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6733   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6734   for (n = 0; n < numNeighbors; ++n) {
6735     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6736   }
6737   depthSizeOld[depth]   = cMax;
6738   depthSizeOld[0]       = vMax;
6739   depthSizeOld[depth-1] = fMax;
6740   depthSizeOld[1]       = eMax;
6741 
6742   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6743   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6744 
6745   depthSizeOld[depth]   = cEnd - cStart;
6746   depthSizeOld[0]       = vEnd - vStart;
6747   depthSizeOld[depth-1] = fEnd - fStart;
6748   depthSizeOld[1]       = eEnd - eStart;
6749 
6750   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6751   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6752   for (n = 0; n < numNeighbors; ++n) {
6753     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6754   }
6755   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6756   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6757   /* Calculate new point SF */
6758   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6759   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6760   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6761   for (l = 0, m = 0; l < numLeaves; ++l) {
6762     PetscInt    p     = localPoints[l];
6763     PetscInt    rp    = remotePoints[l].index, n;
6764     PetscMPIInt rrank = remotePoints[l].rank;
6765 
6766     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6767     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6768     switch (refiner) {
6769     case 1:
6770       /* Simplicial 2D */
6771       if ((p >= vStart) && (p < vEnd)) {
6772         /* Old vertices stay the same */
6773         localPointsNew[m]        = vStartNew     + (p  - vStart);
6774         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6775         remotePointsNew[m].rank  = rrank;
6776         ++m;
6777       } else if ((p >= fStart) && (p < fEnd)) {
6778         /* Old faces add new faces and vertex */
6779         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6780         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6781         remotePointsNew[m].rank  = rrank;
6782         ++m;
6783         for (r = 0; r < 2; ++r, ++m) {
6784           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6785           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6786           remotePointsNew[m].rank  = rrank;
6787         }
6788       } else if ((p >= cStart) && (p < cEnd)) {
6789         /* Old cells add new cells and interior faces */
6790         for (r = 0; r < 4; ++r, ++m) {
6791           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6792           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6793           remotePointsNew[m].rank  = rrank;
6794         }
6795         for (r = 0; r < 3; ++r, ++m) {
6796           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6797           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6798           remotePointsNew[m].rank  = rrank;
6799         }
6800       }
6801       break;
6802     case 2:
6803       /* Hex 2D */
6804       if ((p >= vStart) && (p < vEnd)) {
6805         /* Old vertices stay the same */
6806         localPointsNew[m]        = vStartNew     + (p  - vStart);
6807         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6808         remotePointsNew[m].rank  = rrank;
6809         ++m;
6810       } else if ((p >= fStart) && (p < fEnd)) {
6811         /* Old faces add new faces and vertex */
6812         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6813         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6814         remotePointsNew[m].rank  = rrank;
6815         ++m;
6816         for (r = 0; r < 2; ++r, ++m) {
6817           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6818           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6819           remotePointsNew[m].rank  = rrank;
6820         }
6821       } else if ((p >= cStart) && (p < cEnd)) {
6822         /* Old cells add new cells and interior faces */
6823         for (r = 0; r < 4; ++r, ++m) {
6824           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6825           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6826           remotePointsNew[m].rank  = rrank;
6827         }
6828         for (r = 0; r < 4; ++r, ++m) {
6829           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6830           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6831           remotePointsNew[m].rank  = rrank;
6832         }
6833       }
6834       break;
6835     case 3:
6836       /* Hybrid simplicial 2D */
6837       if ((p >= vStart) && (p < vEnd)) {
6838         /* Old vertices stay the same */
6839         localPointsNew[m]        = vStartNew     + (p  - vStart);
6840         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6841         remotePointsNew[m].rank  = rrank;
6842         ++m;
6843       } else if ((p >= fStart) && (p < fMax)) {
6844         /* Old interior faces add new faces and vertex */
6845         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6846         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6847         remotePointsNew[m].rank  = rrank;
6848         ++m;
6849         for (r = 0; r < 2; ++r, ++m) {
6850           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6851           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6852           remotePointsNew[m].rank  = rrank;
6853         }
6854       } else if ((p >= fMax) && (p < fEnd)) {
6855         /* Old hybrid faces stay the same */
6856         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6857         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6858         remotePointsNew[m].rank  = rrank;
6859         ++m;
6860       } else if ((p >= cStart) && (p < cMax)) {
6861         /* Old interior cells add new cells and interior faces */
6862         for (r = 0; r < 4; ++r, ++m) {
6863           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6864           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6865           remotePointsNew[m].rank  = rrank;
6866         }
6867         for (r = 0; r < 3; ++r, ++m) {
6868           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6869           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6870           remotePointsNew[m].rank  = rrank;
6871         }
6872       } else if ((p >= cStart) && (p < cMax)) {
6873         /* Old hybrid cells add new cells and hybrid face */
6874         for (r = 0; r < 2; ++r, ++m) {
6875           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6876           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6877           remotePointsNew[m].rank  = rrank;
6878         }
6879         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6880         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]);
6881         remotePointsNew[m].rank  = rrank;
6882         ++m;
6883       }
6884       break;
6885     default:
6886       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6887     }
6888   }
6889   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6890   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6891   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6892   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6893   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6894   PetscFunctionReturn(0);
6895 }
6896 
6897 #undef __FUNCT__
6898 #define __FUNCT__ "CellRefinerCreateLabels"
6899 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6900 {
6901   PetscInt       numLabels, l;
6902   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6903   PetscErrorCode ierr;
6904 
6905   PetscFunctionBegin;
6906   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6907   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6908   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6909   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6910 
6911   cStartNew = 0;
6912   vStartNew = depthSize[2];
6913   fStartNew = depthSize[2] + depthSize[0];
6914 
6915   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6916   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6917   switch (refiner) {
6918   case 3:
6919     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6920     cMax = PetscMin(cEnd, cMax);
6921     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6922     fMax = PetscMin(fEnd, fMax);
6923   }
6924   for (l = 0; l < numLabels; ++l) {
6925     DMLabel         label, labelNew;
6926     const char     *lname;
6927     PetscBool       isDepth;
6928     IS              valueIS;
6929     const PetscInt *values;
6930     PetscInt        numValues, val;
6931 
6932     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6933     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6934     if (isDepth) continue;
6935     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6936     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6937     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6938     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6939     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6940     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6941     for (val = 0; val < numValues; ++val) {
6942       IS              pointIS;
6943       const PetscInt *points;
6944       PetscInt        numPoints, n;
6945 
6946       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6947       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6948       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6949       for (n = 0; n < numPoints; ++n) {
6950         const PetscInt p = points[n];
6951         switch (refiner) {
6952         case 1:
6953           /* Simplicial 2D */
6954           if ((p >= vStart) && (p < vEnd)) {
6955             /* Old vertices stay the same */
6956             newp = vStartNew + (p - vStart);
6957             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6958           } else if ((p >= fStart) && (p < fEnd)) {
6959             /* Old faces add new faces and vertex */
6960             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6961             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6962             for (r = 0; r < 2; ++r) {
6963               newp = fStartNew + (p - fStart)*2 + r;
6964               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6965             }
6966           } else if ((p >= cStart) && (p < cEnd)) {
6967             /* Old cells add new cells and interior faces */
6968             for (r = 0; r < 4; ++r) {
6969               newp = cStartNew + (p - cStart)*4 + r;
6970               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6971             }
6972             for (r = 0; r < 3; ++r) {
6973               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6974               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6975             }
6976           }
6977           break;
6978         case 2:
6979           /* Hex 2D */
6980           if ((p >= vStart) && (p < vEnd)) {
6981             /* Old vertices stay the same */
6982             newp = vStartNew + (p - vStart);
6983             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6984           } else if ((p >= fStart) && (p < fEnd)) {
6985             /* Old faces add new faces and vertex */
6986             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6987             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6988             for (r = 0; r < 2; ++r) {
6989               newp = fStartNew + (p - fStart)*2 + r;
6990               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6991             }
6992           } else if ((p >= cStart) && (p < cEnd)) {
6993             /* Old cells add new cells and interior faces and vertex */
6994             for (r = 0; r < 4; ++r) {
6995               newp = cStartNew + (p - cStart)*4 + r;
6996               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6997             }
6998             for (r = 0; r < 4; ++r) {
6999               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7000               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7001             }
7002             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7003             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7004           }
7005           break;
7006         case 3:
7007           /* Hybrid simplicial 2D */
7008           if ((p >= vStart) && (p < vEnd)) {
7009             /* Old vertices stay the same */
7010             newp = vStartNew + (p - vStart);
7011             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7012           } else if ((p >= fStart) && (p < fMax)) {
7013             /* Old interior faces add new faces and vertex */
7014             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7015             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7016             for (r = 0; r < 2; ++r) {
7017               newp = fStartNew + (p - fStart)*2 + r;
7018               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7019             }
7020           } else if ((p >= fMax) && (p < fEnd)) {
7021             /* Old hybrid faces stay the same */
7022             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7023             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7024           } else if ((p >= cStart) && (p < cMax)) {
7025             /* Old interior cells add new cells and interior faces */
7026             for (r = 0; r < 4; ++r) {
7027               newp = cStartNew + (p - cStart)*4 + r;
7028               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7029             }
7030             for (r = 0; r < 3; ++r) {
7031               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7032               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7033             }
7034           } else if ((p >= cMax) && (p < cEnd)) {
7035             /* Old hybrid cells add new cells and hybrid face */
7036             for (r = 0; r < 2; ++r) {
7037               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7038               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7039             }
7040             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7041             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7042           }
7043           break;
7044         default:
7045           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7046         }
7047       }
7048       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7049       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7050     }
7051     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7052     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7053     if (0) {
7054       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7055       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7056       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7057     }
7058   }
7059   PetscFunctionReturn(0);
7060 }
7061 
7062 #undef __FUNCT__
7063 #define __FUNCT__ "DMPlexRefine_Uniform"
7064 /* This will only work for interpolated meshes */
7065 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7066 {
7067   DM             rdm;
7068   PetscInt      *depthSize;
7069   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7070   PetscErrorCode ierr;
7071 
7072   PetscFunctionBegin;
7073   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7074   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7075   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7076   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7077   /* Calculate number of new points of each depth */
7078   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7079   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7080   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7081   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7082   /* Step 1: Set chart */
7083   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7084   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7085   /* Step 2: Set cone/support sizes */
7086   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7087   /* Step 3: Setup refined DM */
7088   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7089   /* Step 4: Set cones and supports */
7090   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7091   /* Step 5: Stratify */
7092   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7093   /* Step 6: Set coordinates for vertices */
7094   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7095   /* Step 7: Create pointSF */
7096   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7097   /* Step 8: Create labels */
7098   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7099   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7100 
7101   *dmRefined = rdm;
7102   PetscFunctionReturn(0);
7103 }
7104 
7105 #undef __FUNCT__
7106 #define __FUNCT__ "DMPlexSetRefinementUniform"
7107 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7108 {
7109   DM_Plex *mesh = (DM_Plex*) dm->data;
7110 
7111   PetscFunctionBegin;
7112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7113   mesh->refinementUniform = refinementUniform;
7114   PetscFunctionReturn(0);
7115 }
7116 
7117 #undef __FUNCT__
7118 #define __FUNCT__ "DMPlexGetRefinementUniform"
7119 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7120 {
7121   DM_Plex *mesh = (DM_Plex*) dm->data;
7122 
7123   PetscFunctionBegin;
7124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7125   PetscValidPointer(refinementUniform,  2);
7126   *refinementUniform = mesh->refinementUniform;
7127   PetscFunctionReturn(0);
7128 }
7129 
7130 #undef __FUNCT__
7131 #define __FUNCT__ "DMPlexSetRefinementLimit"
7132 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7133 {
7134   DM_Plex *mesh = (DM_Plex*) dm->data;
7135 
7136   PetscFunctionBegin;
7137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7138   mesh->refinementLimit = refinementLimit;
7139   PetscFunctionReturn(0);
7140 }
7141 
7142 #undef __FUNCT__
7143 #define __FUNCT__ "DMPlexGetRefinementLimit"
7144 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7145 {
7146   DM_Plex *mesh = (DM_Plex*) dm->data;
7147 
7148   PetscFunctionBegin;
7149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7150   PetscValidPointer(refinementLimit,  2);
7151   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7152   *refinementLimit = mesh->refinementLimit;
7153   PetscFunctionReturn(0);
7154 }
7155 
7156 #undef __FUNCT__
7157 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7158 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7159 {
7160   PetscInt       dim, cStart, coneSize, cMax;
7161   PetscErrorCode ierr;
7162 
7163   PetscFunctionBegin;
7164   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7165   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7166   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7167   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7168   switch (dim) {
7169   case 2:
7170     switch (coneSize) {
7171     case 3:
7172       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7173       else *cellRefiner = 1; /* Triangular */
7174       break;
7175     case 4:
7176       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7177       else *cellRefiner = 2; /* Quadrilateral */
7178       break;
7179     default:
7180       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7181     }
7182     break;
7183   default:
7184     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7185   }
7186   PetscFunctionReturn(0);
7187 }
7188 
7189 #undef __FUNCT__
7190 #define __FUNCT__ "DMRefine_Plex"
7191 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7192 {
7193   PetscReal      refinementLimit;
7194   PetscInt       dim, cStart, cEnd;
7195   char           genname[1024], *name = NULL;
7196   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7197   PetscErrorCode ierr;
7198 
7199   PetscFunctionBegin;
7200   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7201   if (isUniform) {
7202     CellRefiner cellRefiner;
7203 
7204     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7205     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7206     PetscFunctionReturn(0);
7207   }
7208   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7209   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7210   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7211   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7212   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7213   if (flg) name = genname;
7214   if (name) {
7215     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7216     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7217     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7218   }
7219   switch (dim) {
7220   case 2:
7221     if (!name || isTriangle) {
7222 #if defined(PETSC_HAVE_TRIANGLE)
7223       double  *maxVolumes;
7224       PetscInt c;
7225 
7226       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7227       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7228       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7229 #else
7230       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7231 #endif
7232     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7233     break;
7234   case 3:
7235     if (!name || isCTetgen) {
7236 #if defined(PETSC_HAVE_CTETGEN)
7237       PetscReal *maxVolumes;
7238       PetscInt   c;
7239 
7240       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7241       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7242       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7243 #else
7244       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7245 #endif
7246     } else if (isTetgen) {
7247 #if defined(PETSC_HAVE_TETGEN)
7248       double  *maxVolumes;
7249       PetscInt c;
7250 
7251       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7252       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7253       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7254 #else
7255       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7256 #endif
7257     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7258     break;
7259   default:
7260     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7261   }
7262   PetscFunctionReturn(0);
7263 }
7264 
7265 #undef __FUNCT__
7266 #define __FUNCT__ "DMPlexGetDepth"
7267 /*@
7268   DMPlexGetDepth - get the number of strata
7269 
7270   Not Collective
7271 
7272   Input Parameters:
7273 . dm           - The DMPlex object
7274 
7275   Output Parameters:
7276 . depth - number of strata
7277 
7278   Level: developer
7279 
7280   Notes:
7281   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7282 
7283 .keywords: mesh, points
7284 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7285 @*/
7286 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7287 {
7288   PetscInt       d;
7289   PetscErrorCode ierr;
7290 
7291   PetscFunctionBegin;
7292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7293   PetscValidPointer(depth, 2);
7294   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7295   *depth = d-1;
7296   PetscFunctionReturn(0);
7297 }
7298 
7299 #undef __FUNCT__
7300 #define __FUNCT__ "DMPlexGetDepthStratum"
7301 /*@
7302   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7303 
7304   Not Collective
7305 
7306   Input Parameters:
7307 + dm           - The DMPlex object
7308 - stratumValue - The requested depth
7309 
7310   Output Parameters:
7311 + start - The first point at this depth
7312 - end   - One beyond the last point at this depth
7313 
7314   Level: developer
7315 
7316 .keywords: mesh, points
7317 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7318 @*/
7319 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7320 {
7321   DM_Plex       *mesh = (DM_Plex*) dm->data;
7322   DMLabel        next  = mesh->labels;
7323   PetscBool      flg   = PETSC_FALSE;
7324   PetscInt       depth;
7325   PetscErrorCode ierr;
7326 
7327   PetscFunctionBegin;
7328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7329   if (stratumValue < 0) {
7330     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7331     PetscFunctionReturn(0);
7332   } else {
7333     PetscInt pStart, pEnd;
7334 
7335     if (start) *start = 0;
7336     if (end)   *end   = 0;
7337     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7338     if (pStart == pEnd) PetscFunctionReturn(0);
7339   }
7340   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7341   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7342   /* We should have a generic GetLabel() and a Label class */
7343   while (next) {
7344     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7345     if (flg) break;
7346     next = next->next;
7347   }
7348   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7349   depth = stratumValue;
7350   if ((depth < 0) || (depth >= next->numStrata)) {
7351     if (start) *start = 0;
7352     if (end)   *end   = 0;
7353   } else {
7354     if (start) *start = next->points[next->stratumOffsets[depth]];
7355     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7356   }
7357   PetscFunctionReturn(0);
7358 }
7359 
7360 #undef __FUNCT__
7361 #define __FUNCT__ "DMPlexGetHeightStratum"
7362 /*@
7363   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7364 
7365   Not Collective
7366 
7367   Input Parameters:
7368 + dm           - The DMPlex object
7369 - stratumValue - The requested height
7370 
7371   Output Parameters:
7372 + start - The first point at this height
7373 - end   - One beyond the last point at this height
7374 
7375   Level: developer
7376 
7377 .keywords: mesh, points
7378 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7379 @*/
7380 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7381 {
7382   DM_Plex       *mesh = (DM_Plex*) dm->data;
7383   DMLabel        next  = mesh->labels;
7384   PetscBool      flg   = PETSC_FALSE;
7385   PetscInt       depth;
7386   PetscErrorCode ierr;
7387 
7388   PetscFunctionBegin;
7389   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7390   if (stratumValue < 0) {
7391     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7392   } else {
7393     PetscInt pStart, pEnd;
7394 
7395     if (start) *start = 0;
7396     if (end)   *end   = 0;
7397     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7398     if (pStart == pEnd) PetscFunctionReturn(0);
7399   }
7400   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7401   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7402   /* We should have a generic GetLabel() and a Label class */
7403   while (next) {
7404     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7405     if (flg) break;
7406     next = next->next;
7407   }
7408   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7409   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7410   if ((depth < 0) || (depth >= next->numStrata)) {
7411     if (start) *start = 0;
7412     if (end)   *end   = 0;
7413   } else {
7414     if (start) *start = next->points[next->stratumOffsets[depth]];
7415     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7416   }
7417   PetscFunctionReturn(0);
7418 }
7419 
7420 #undef __FUNCT__
7421 #define __FUNCT__ "DMPlexCreateSectionInitial"
7422 /* Set the number of dof on each point and separate by fields */
7423 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7424 {
7425   PetscInt      *numDofTot;
7426   PetscInt       pStart = 0, pEnd = 0;
7427   PetscInt       p, d, f;
7428   PetscErrorCode ierr;
7429 
7430   PetscFunctionBegin;
7431   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7432   for (d = 0; d <= dim; ++d) {
7433     numDofTot[d] = 0;
7434     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7435   }
7436   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7437   if (numFields > 0) {
7438     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7439     if (numComp) {
7440       for (f = 0; f < numFields; ++f) {
7441         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7442       }
7443     }
7444   }
7445   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7446   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7447   for (d = 0; d <= dim; ++d) {
7448     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7449     for (p = pStart; p < pEnd; ++p) {
7450       for (f = 0; f < numFields; ++f) {
7451         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7452       }
7453       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7454     }
7455   }
7456   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7457   PetscFunctionReturn(0);
7458 }
7459 
7460 #undef __FUNCT__
7461 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7462 /* Set the number of dof on each point and separate by fields
7463    If constDof is PETSC_DETERMINE, constrain every dof on the point
7464 */
7465 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7466 {
7467   PetscInt       numFields;
7468   PetscInt       bc;
7469   PetscErrorCode ierr;
7470 
7471   PetscFunctionBegin;
7472   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7473   for (bc = 0; bc < numBC; ++bc) {
7474     PetscInt        field = 0;
7475     const PetscInt *idx;
7476     PetscInt        n, i;
7477 
7478     if (numFields) field = bcField[bc];
7479     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7480     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7481     for (i = 0; i < n; ++i) {
7482       const PetscInt p        = idx[i];
7483       PetscInt       numConst = constDof;
7484 
7485       /* Constrain every dof on the point */
7486       if (numConst < 0) {
7487         if (numFields) {
7488           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7489         } else {
7490           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7491         }
7492       }
7493       if (numFields) {
7494         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7495       }
7496       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7497     }
7498     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7499   }
7500   PetscFunctionReturn(0);
7501 }
7502 
7503 #undef __FUNCT__
7504 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7505 /* Set the constrained indices on each point and separate by fields */
7506 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7507 {
7508   PetscInt      *maxConstraints;
7509   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7510   PetscErrorCode ierr;
7511 
7512   PetscFunctionBegin;
7513   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7514   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7515   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7516   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7517   for (p = pStart; p < pEnd; ++p) {
7518     PetscInt cdof;
7519 
7520     if (numFields) {
7521       for (f = 0; f < numFields; ++f) {
7522         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7523         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7524       }
7525     } else {
7526       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7527       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7528     }
7529   }
7530   for (f = 0; f < numFields; ++f) {
7531     maxConstraints[numFields] += maxConstraints[f];
7532   }
7533   if (maxConstraints[numFields]) {
7534     PetscInt *indices;
7535 
7536     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7537     for (p = pStart; p < pEnd; ++p) {
7538       PetscInt cdof, d;
7539 
7540       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7541       if (cdof) {
7542         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7543         if (numFields) {
7544           PetscInt numConst = 0, foff = 0;
7545 
7546           for (f = 0; f < numFields; ++f) {
7547             PetscInt cfdof, fdof;
7548 
7549             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7550             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7551             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7552             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7553             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7554             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7555             numConst += cfdof;
7556             foff     += fdof;
7557           }
7558           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7559         } else {
7560           for (d = 0; d < cdof; ++d) indices[d] = d;
7561         }
7562         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7563       }
7564     }
7565     ierr = PetscFree(indices);CHKERRQ(ierr);
7566   }
7567   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7568   PetscFunctionReturn(0);
7569 }
7570 
7571 #undef __FUNCT__
7572 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7573 /* Set the constrained field indices on each point */
7574 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7575 {
7576   const PetscInt *points, *indices;
7577   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7578   PetscErrorCode  ierr;
7579 
7580   PetscFunctionBegin;
7581   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7582   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7583 
7584   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7585   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7586   if (!constraintIndices) {
7587     PetscInt *idx, i;
7588 
7589     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7590     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7591     for (i = 0; i < maxDof; ++i) idx[i] = i;
7592     for (p = 0; p < numPoints; ++p) {
7593       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7594     }
7595     ierr = PetscFree(idx);CHKERRQ(ierr);
7596   } else {
7597     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7598     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7599     for (p = 0; p < numPoints; ++p) {
7600       PetscInt fcdof;
7601 
7602       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7603       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);
7604       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7605     }
7606     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7607   }
7608   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7609   PetscFunctionReturn(0);
7610 }
7611 
7612 #undef __FUNCT__
7613 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7614 /* Set the constrained indices on each point and separate by fields */
7615 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7616 {
7617   PetscInt      *indices;
7618   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7619   PetscErrorCode ierr;
7620 
7621   PetscFunctionBegin;
7622   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7623   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7624   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7625   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7626   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7627   for (p = pStart; p < pEnd; ++p) {
7628     PetscInt cdof, d;
7629 
7630     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7631     if (cdof) {
7632       PetscInt numConst = 0, foff = 0;
7633 
7634       for (f = 0; f < numFields; ++f) {
7635         const PetscInt *fcind;
7636         PetscInt        fdof, fcdof;
7637 
7638         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7639         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7640         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7641         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7642         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7643         foff     += fdof;
7644         numConst += fcdof;
7645       }
7646       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7647       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7648     }
7649   }
7650   ierr = PetscFree(indices);CHKERRQ(ierr);
7651   PetscFunctionReturn(0);
7652 }
7653 
7654 #undef __FUNCT__
7655 #define __FUNCT__ "DMPlexCreateSection"
7656 /*@C
7657   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7658 
7659   Not Collective
7660 
7661   Input Parameters:
7662 + dm        - The DMPlex object
7663 . dim       - The spatial dimension of the problem
7664 . numFields - The number of fields in the problem
7665 . numComp   - An array of size numFields that holds the number of components for each field
7666 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7667 . numBC     - The number of boundary conditions
7668 . bcField   - An array of size numBC giving the field number for each boundry condition
7669 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7670 
7671   Output Parameter:
7672 . section - The PetscSection object
7673 
7674   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
7675   nubmer of dof for field 0 on each edge.
7676 
7677   Level: developer
7678 
7679 .keywords: mesh, elements
7680 .seealso: DMPlexCreate(), PetscSectionCreate()
7681 @*/
7682 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7683 {
7684   PetscErrorCode ierr;
7685 
7686   PetscFunctionBegin;
7687   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7688   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7689   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7690   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7691   {
7692     PetscBool view = PETSC_FALSE;
7693 
7694     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7695     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7696   }
7697   PetscFunctionReturn(0);
7698 }
7699 
7700 #undef __FUNCT__
7701 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7702 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7703 {
7704   PetscSection   section;
7705   PetscErrorCode ierr;
7706 
7707   PetscFunctionBegin;
7708   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7709   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7710   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7711   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7712   PetscFunctionReturn(0);
7713 }
7714 
7715 #undef __FUNCT__
7716 #define __FUNCT__ "DMPlexGetCoordinateSection"
7717 /*@
7718   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7719 
7720   Not Collective
7721 
7722   Input Parameter:
7723 . dm - The DMPlex object
7724 
7725   Output Parameter:
7726 . section - The PetscSection object
7727 
7728   Level: intermediate
7729 
7730 .keywords: mesh, coordinates
7731 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7732 @*/
7733 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7734 {
7735   DM             cdm;
7736   PetscErrorCode ierr;
7737 
7738   PetscFunctionBegin;
7739   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7740   PetscValidPointer(section, 2);
7741   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7742   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7743   PetscFunctionReturn(0);
7744 }
7745 
7746 #undef __FUNCT__
7747 #define __FUNCT__ "DMPlexSetCoordinateSection"
7748 /*@
7749   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7750 
7751   Not Collective
7752 
7753   Input Parameters:
7754 + dm      - The DMPlex object
7755 - section - The PetscSection object
7756 
7757   Level: intermediate
7758 
7759 .keywords: mesh, coordinates
7760 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7761 @*/
7762 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7763 {
7764   DM             cdm;
7765   PetscErrorCode ierr;
7766 
7767   PetscFunctionBegin;
7768   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7769   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7770   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7771   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7772   PetscFunctionReturn(0);
7773 }
7774 
7775 #undef __FUNCT__
7776 #define __FUNCT__ "DMPlexGetConeSection"
7777 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7778 {
7779   DM_Plex *mesh = (DM_Plex*) dm->data;
7780 
7781   PetscFunctionBegin;
7782   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7783   if (section) *section = mesh->coneSection;
7784   PetscFunctionReturn(0);
7785 }
7786 
7787 #undef __FUNCT__
7788 #define __FUNCT__ "DMPlexGetCones"
7789 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7790 {
7791   DM_Plex *mesh = (DM_Plex*) dm->data;
7792 
7793   PetscFunctionBegin;
7794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7795   if (cones) *cones = mesh->cones;
7796   PetscFunctionReturn(0);
7797 }
7798 
7799 #undef __FUNCT__
7800 #define __FUNCT__ "DMPlexGetConeOrientations"
7801 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7802 {
7803   DM_Plex *mesh = (DM_Plex*) dm->data;
7804 
7805   PetscFunctionBegin;
7806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7807   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7808   PetscFunctionReturn(0);
7809 }
7810 
7811 #undef __FUNCT__
7812 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7813 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7814 {
7815   const PetscInt embedDim = 2;
7816   PetscReal      x        = PetscRealPart(point[0]);
7817   PetscReal      y        = PetscRealPart(point[1]);
7818   PetscReal      v0[2], J[4], invJ[4], detJ;
7819   PetscReal      xi, eta;
7820   PetscErrorCode ierr;
7821 
7822   PetscFunctionBegin;
7823   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7824   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7825   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7826 
7827   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7828   else *cell = -1;
7829   PetscFunctionReturn(0);
7830 }
7831 
7832 #undef __FUNCT__
7833 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7834 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7835 {
7836   PetscSection       coordSection;
7837   Vec                coordsLocal;
7838   const PetscScalar *coords;
7839   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7840   PetscReal          x         = PetscRealPart(point[0]);
7841   PetscReal          y         = PetscRealPart(point[1]);
7842   PetscInt           crossings = 0, f;
7843   PetscErrorCode     ierr;
7844 
7845   PetscFunctionBegin;
7846   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7847   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7848   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7849   for (f = 0; f < 4; ++f) {
7850     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7851     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7852     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7853     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7854     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7855     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7856     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7857     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7858     if ((cond1 || cond2)  && above) ++crossings;
7859   }
7860   if (crossings % 2) *cell = c;
7861   else *cell = -1;
7862   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7863   PetscFunctionReturn(0);
7864 }
7865 
7866 #undef __FUNCT__
7867 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7868 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7869 {
7870   const PetscInt embedDim = 3;
7871   PetscReal      v0[3], J[9], invJ[9], detJ;
7872   PetscReal      x = PetscRealPart(point[0]);
7873   PetscReal      y = PetscRealPart(point[1]);
7874   PetscReal      z = PetscRealPart(point[2]);
7875   PetscReal      xi, eta, zeta;
7876   PetscErrorCode ierr;
7877 
7878   PetscFunctionBegin;
7879   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7880   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7881   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7882   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7883 
7884   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7885   else *cell = -1;
7886   PetscFunctionReturn(0);
7887 }
7888 
7889 #undef __FUNCT__
7890 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7891 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7892 {
7893   PetscSection       coordSection;
7894   Vec                coordsLocal;
7895   const PetscScalar *coords;
7896   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7897                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7898   PetscBool          found = PETSC_TRUE;
7899   PetscInt           f;
7900   PetscErrorCode     ierr;
7901 
7902   PetscFunctionBegin;
7903   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7904   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7905   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7906   for (f = 0; f < 6; ++f) {
7907     /* Check the point is under plane */
7908     /*   Get face normal */
7909     PetscReal v_i[3];
7910     PetscReal v_j[3];
7911     PetscReal normal[3];
7912     PetscReal pp[3];
7913     PetscReal dot;
7914 
7915     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7916     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7917     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7918     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7919     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7920     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7921     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7922     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7923     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7924     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7925     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7926     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7927     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7928 
7929     /* Check that projected point is in face (2D location problem) */
7930     if (dot < 0.0) {
7931       found = PETSC_FALSE;
7932       break;
7933     }
7934   }
7935   if (found) *cell = c;
7936   else *cell = -1;
7937   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7938   PetscFunctionReturn(0);
7939 }
7940 
7941 #undef __FUNCT__
7942 #define __FUNCT__ "DMLocatePoints_Plex"
7943 /*
7944  Need to implement using the guess
7945 */
7946 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7947 {
7948   PetscInt       cell = -1 /*, guess = -1*/;
7949   PetscInt       bs, numPoints, p;
7950   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7951   PetscInt      *cells;
7952   PetscScalar   *a;
7953   PetscErrorCode ierr;
7954 
7955   PetscFunctionBegin;
7956   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7957   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7958   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7959   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7960   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7961   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7962   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7963   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);
7964   numPoints /= bs;
7965   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7966   for (p = 0; p < numPoints; ++p) {
7967     const PetscScalar *point = &a[p*bs];
7968 
7969     switch (dim) {
7970     case 2:
7971       for (c = cStart; c < cEnd; ++c) {
7972         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7973         switch (coneSize) {
7974         case 3:
7975           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7976           break;
7977         case 4:
7978           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7979           break;
7980         default:
7981           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7982         }
7983         if (cell >= 0) break;
7984       }
7985       break;
7986     case 3:
7987       for (c = cStart; c < cEnd; ++c) {
7988         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7989         switch (coneSize) {
7990         case 4:
7991           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7992           break;
7993         case 8:
7994           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7995           break;
7996         default:
7997           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7998         }
7999         if (cell >= 0) break;
8000       }
8001       break;
8002     default:
8003       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8004     }
8005     cells[p] = cell;
8006   }
8007   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8008   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8009   PetscFunctionReturn(0);
8010 }
8011 
8012 /******************************** FEM Support **********************************/
8013 
8014 #undef __FUNCT__
8015 #define __FUNCT__ "DMPlexVecGetClosure"
8016 /*@C
8017   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8018 
8019   Not collective
8020 
8021   Input Parameters:
8022 + dm - The DM
8023 . section - The section describing the layout in v, or NULL to use the default section
8024 . v - The local vector
8025 - point - The sieve point in the DM
8026 
8027   Output Parameters:
8028 + csize - The number of values in the closure, or NULL
8029 - values - The array of values, which is a borrowed array and should not be freed
8030 
8031   Level: intermediate
8032 
8033 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8034 @*/
8035 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8036 {
8037   PetscScalar   *array, *vArray;
8038   PetscInt      *points = NULL;
8039   PetscInt       offsets[32];
8040   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8041   PetscErrorCode ierr;
8042 
8043   PetscFunctionBegin;
8044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8045   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8046   if (!section) {
8047     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8048   }
8049   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8050   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8051   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8052   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8053   /* Compress out points not in the section */
8054   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8055   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8056     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8057       points[q*2]   = points[p];
8058       points[q*2+1] = points[p+1];
8059       ++q;
8060     }
8061   }
8062   numPoints = q;
8063   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8064     PetscInt dof, fdof;
8065 
8066     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8067     for (f = 0; f < numFields; ++f) {
8068       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8069       offsets[f+1] += fdof;
8070     }
8071     size += dof;
8072   }
8073   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8074   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8075   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8076   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8077   for (p = 0; p < numPoints*2; p += 2) {
8078     PetscInt     o = points[p+1];
8079     PetscInt     dof, off, d;
8080     PetscScalar *varr;
8081 
8082     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8083     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8084     varr = &vArray[off];
8085     if (numFields) {
8086       PetscInt fdof, foff, fcomp, f, c;
8087 
8088       for (f = 0, foff = 0; f < numFields; ++f) {
8089         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8090         if (o >= 0) {
8091           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8092             array[offsets[f]] = varr[foff+d];
8093           }
8094         } else {
8095           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8096           for (d = fdof/fcomp-1; d >= 0; --d) {
8097             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8098               array[offsets[f]] = varr[foff+d*fcomp+c];
8099             }
8100           }
8101         }
8102         foff += fdof;
8103       }
8104     } else {
8105       if (o >= 0) {
8106         for (d = 0; d < dof; ++d, ++offsets[0]) {
8107           array[offsets[0]] = varr[d];
8108         }
8109       } else {
8110         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8111           array[offsets[0]] = varr[d];
8112         }
8113       }
8114     }
8115   }
8116   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8117   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8118   if (csize) *csize = size;
8119   *values = array;
8120   PetscFunctionReturn(0);
8121 }
8122 
8123 #undef __FUNCT__
8124 #define __FUNCT__ "DMPlexVecRestoreClosure"
8125 /*@C
8126   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8127 
8128   Not collective
8129 
8130   Input Parameters:
8131 + dm - The DM
8132 . section - The section describing the layout in v, or NULL to use the default section
8133 . v - The local vector
8134 . point - The sieve point in the DM
8135 . csize - The number of values in the closure, or NULL
8136 - values - The array of values, which is a borrowed array and should not be freed
8137 
8138   Level: intermediate
8139 
8140 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8141 @*/
8142 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8143 {
8144   PetscInt       size = 0;
8145   PetscErrorCode ierr;
8146 
8147   PetscFunctionBegin;
8148   /* Should work without recalculating size */
8149   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8150   PetscFunctionReturn(0);
8151 }
8152 
8153 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8154 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8155 
8156 #undef __FUNCT__
8157 #define __FUNCT__ "updatePoint_private"
8158 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8159 {
8160   PetscInt        cdof;   /* The number of constraints on this point */
8161   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8162   PetscScalar    *a;
8163   PetscInt        off, cind = 0, k;
8164   PetscErrorCode  ierr;
8165 
8166   PetscFunctionBegin;
8167   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8168   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8169   a    = &array[off];
8170   if (!cdof || setBC) {
8171     if (orientation >= 0) {
8172       for (k = 0; k < dof; ++k) {
8173         fuse(&a[k], values[k]);
8174       }
8175     } else {
8176       for (k = 0; k < dof; ++k) {
8177         fuse(&a[k], values[dof-k-1]);
8178       }
8179     }
8180   } else {
8181     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8182     if (orientation >= 0) {
8183       for (k = 0; k < dof; ++k) {
8184         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8185         fuse(&a[k], values[k]);
8186       }
8187     } else {
8188       for (k = 0; k < dof; ++k) {
8189         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8190         fuse(&a[k], values[dof-k-1]);
8191       }
8192     }
8193   }
8194   PetscFunctionReturn(0);
8195 }
8196 
8197 #undef __FUNCT__
8198 #define __FUNCT__ "updatePointFields_private"
8199 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8200 {
8201   PetscScalar   *a;
8202   PetscInt       numFields, off, foff, f;
8203   PetscErrorCode ierr;
8204 
8205   PetscFunctionBegin;
8206   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8207   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8208   a    = &array[off];
8209   for (f = 0, foff = 0; f < numFields; ++f) {
8210     PetscInt        fdof, fcomp, fcdof;
8211     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8212     PetscInt        cind = 0, k, c;
8213 
8214     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8215     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8216     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8217     if (!fcdof || setBC) {
8218       if (orientation >= 0) {
8219         for (k = 0; k < fdof; ++k) {
8220           fuse(&a[foff+k], values[foffs[f]+k]);
8221         }
8222       } else {
8223         for (k = fdof/fcomp-1; k >= 0; --k) {
8224           for (c = 0; c < fcomp; ++c) {
8225             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8226           }
8227         }
8228       }
8229     } else {
8230       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8231       if (orientation >= 0) {
8232         for (k = 0; k < fdof; ++k) {
8233           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8234           fuse(&a[foff+k], values[foffs[f]+k]);
8235         }
8236       } else {
8237         for (k = fdof/fcomp-1; k >= 0; --k) {
8238           for (c = 0; c < fcomp; ++c) {
8239             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8240             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8241           }
8242         }
8243       }
8244     }
8245     foff     += fdof;
8246     foffs[f] += fdof;
8247   }
8248   PetscFunctionReturn(0);
8249 }
8250 
8251 #undef __FUNCT__
8252 #define __FUNCT__ "DMPlexVecSetClosure"
8253 /*@C
8254   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8255 
8256   Not collective
8257 
8258   Input Parameters:
8259 + dm - The DM
8260 . section - The section describing the layout in v, or NULL to use the default sectionw
8261 . v - The local vector
8262 . point - The sieve point in the DM
8263 . values - The array of values, which is a borrowed array and should not be freed
8264 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8265 
8266   Level: intermediate
8267 
8268 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8269 @*/
8270 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8271 {
8272   PetscScalar   *array;
8273   PetscInt      *points = NULL;
8274   PetscInt       offsets[32];
8275   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8276   PetscErrorCode ierr;
8277 
8278   PetscFunctionBegin;
8279   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8280   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8281   if (!section) {
8282     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8283   }
8284   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8285   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8286   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8287   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8288   /* Compress out points not in the section */
8289   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8290   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8291     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8292       points[q*2]   = points[p];
8293       points[q*2+1] = points[p+1];
8294       ++q;
8295     }
8296   }
8297   numPoints = q;
8298   for (p = 0; p < numPoints*2; p += 2) {
8299     PetscInt fdof;
8300 
8301     for (f = 0; f < numFields; ++f) {
8302       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8303       offsets[f+1] += fdof;
8304     }
8305   }
8306   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8307   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8308   if (numFields) {
8309     switch (mode) {
8310     case INSERT_VALUES:
8311       for (p = 0; p < numPoints*2; p += 2) {
8312         PetscInt o = points[p+1];
8313         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8314       } break;
8315     case INSERT_ALL_VALUES:
8316       for (p = 0; p < numPoints*2; p += 2) {
8317         PetscInt o = points[p+1];
8318         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8319       } break;
8320     case ADD_VALUES:
8321       for (p = 0; p < numPoints*2; p += 2) {
8322         PetscInt o = points[p+1];
8323         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8324       } break;
8325     case ADD_ALL_VALUES:
8326       for (p = 0; p < numPoints*2; p += 2) {
8327         PetscInt o = points[p+1];
8328         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8329       } break;
8330     default:
8331       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8332     }
8333   } else {
8334     switch (mode) {
8335     case INSERT_VALUES:
8336       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8337         PetscInt o = points[p+1];
8338         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8339         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8340       } break;
8341     case INSERT_ALL_VALUES:
8342       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8343         PetscInt o = points[p+1];
8344         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8345         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8346       } break;
8347     case ADD_VALUES:
8348       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8349         PetscInt o = points[p+1];
8350         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8351         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8352       } break;
8353     case ADD_ALL_VALUES:
8354       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8355         PetscInt o = points[p+1];
8356         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8357         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8358       } break;
8359     default:
8360       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8361     }
8362   }
8363   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8364   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8365   PetscFunctionReturn(0);
8366 }
8367 
8368 #undef __FUNCT__
8369 #define __FUNCT__ "DMPlexPrintMatSetValues"
8370 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8371 {
8372   PetscMPIInt    rank;
8373   PetscInt       i, j;
8374   PetscErrorCode ierr;
8375 
8376   PetscFunctionBegin;
8377   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8378   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8379   for (i = 0; i < numIndices; i++) {
8380     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8381   }
8382   for (i = 0; i < numIndices; i++) {
8383     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8384     for (j = 0; j < numIndices; j++) {
8385 #if defined(PETSC_USE_COMPLEX)
8386       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8387 #else
8388       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8389 #endif
8390     }
8391     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8392   }
8393   PetscFunctionReturn(0);
8394 }
8395 
8396 #undef __FUNCT__
8397 #define __FUNCT__ "indicesPoint_private"
8398 /* . off - The global offset of this point */
8399 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8400 {
8401   PetscInt        dof;    /* The number of unknowns on this point */
8402   PetscInt        cdof;   /* The number of constraints on this point */
8403   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8404   PetscInt        cind = 0, k;
8405   PetscErrorCode  ierr;
8406 
8407   PetscFunctionBegin;
8408   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8409   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8410   if (!cdof || setBC) {
8411     if (orientation >= 0) {
8412       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8413     } else {
8414       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8415     }
8416   } else {
8417     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8418     if (orientation >= 0) {
8419       for (k = 0; k < dof; ++k) {
8420         if ((cind < cdof) && (k == cdofs[cind])) {
8421           /* Insert check for returning constrained indices */
8422           indices[*loff+k] = -(off+k+1);
8423           ++cind;
8424         } else {
8425           indices[*loff+k] = off+k-cind;
8426         }
8427       }
8428     } else {
8429       for (k = 0; k < dof; ++k) {
8430         if ((cind < cdof) && (k == cdofs[cind])) {
8431           /* Insert check for returning constrained indices */
8432           indices[*loff+dof-k-1] = -(off+k+1);
8433           ++cind;
8434         } else {
8435           indices[*loff+dof-k-1] = off+k-cind;
8436         }
8437       }
8438     }
8439   }
8440   *loff += dof;
8441   PetscFunctionReturn(0);
8442 }
8443 
8444 #undef __FUNCT__
8445 #define __FUNCT__ "indicesPointFields_private"
8446 /* . off - The global offset of this point */
8447 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8448 {
8449   PetscInt       numFields, foff, f;
8450   PetscErrorCode ierr;
8451 
8452   PetscFunctionBegin;
8453   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8454   for (f = 0, foff = 0; f < numFields; ++f) {
8455     PetscInt        fdof, fcomp, cfdof;
8456     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8457     PetscInt        cind = 0, k, c;
8458 
8459     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8460     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8461     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8462     if (!cfdof || setBC) {
8463       if (orientation >= 0) {
8464         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8465       } else {
8466         for (k = fdof/fcomp-1; k >= 0; --k) {
8467           for (c = 0; c < fcomp; ++c) {
8468             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8469           }
8470         }
8471       }
8472     } else {
8473       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8474       if (orientation >= 0) {
8475         for (k = 0; k < fdof; ++k) {
8476           if ((cind < cfdof) && (k == fcdofs[cind])) {
8477             indices[foffs[f]+k] = -(off+foff+k+1);
8478             ++cind;
8479           } else {
8480             indices[foffs[f]+k] = off+foff+k-cind;
8481           }
8482         }
8483       } else {
8484         for (k = fdof/fcomp-1; k >= 0; --k) {
8485           for (c = 0; c < fcomp; ++c) {
8486             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8487               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8488               ++cind;
8489             } else {
8490               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8491             }
8492           }
8493         }
8494       }
8495     }
8496     foff     += fdof - cfdof;
8497     foffs[f] += fdof;
8498   }
8499   PetscFunctionReturn(0);
8500 }
8501 
8502 #undef __FUNCT__
8503 #define __FUNCT__ "DMPlexMatSetClosure"
8504 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8505 {
8506   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8507   PetscInt      *points = NULL;
8508   PetscInt      *indices;
8509   PetscInt       offsets[32];
8510   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8511   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8512   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8513   PetscErrorCode ierr;
8514 
8515   PetscFunctionBegin;
8516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8517   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8518   if (useDefault) {
8519     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8520   }
8521   if (useGlobalDefault) {
8522     if (useDefault) {
8523       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8524     } else {
8525       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8526     }
8527   }
8528   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8529   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8530   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8531   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8532   /* Compress out points not in the section */
8533   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8534   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8535     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8536       points[q*2]   = points[p];
8537       points[q*2+1] = points[p+1];
8538       ++q;
8539     }
8540   }
8541   numPoints = q;
8542   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8543     PetscInt fdof;
8544 
8545     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8546     for (f = 0; f < numFields; ++f) {
8547       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8548       offsets[f+1] += fdof;
8549     }
8550     numIndices += dof;
8551   }
8552   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8553 
8554   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8555   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8556   if (numFields) {
8557     for (p = 0; p < numPoints*2; p += 2) {
8558       PetscInt o = points[p+1];
8559       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8560       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8561     }
8562   } else {
8563     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8564       PetscInt o = points[p+1];
8565       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8566       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8567     }
8568   }
8569   if (useGlobalDefault && !useDefault) {
8570     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8571   }
8572   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8573   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8574   if (ierr) {
8575     PetscMPIInt    rank;
8576     PetscErrorCode ierr2;
8577 
8578     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8579     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8580     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8581     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8582     CHKERRQ(ierr);
8583   }
8584   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8585   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8586   PetscFunctionReturn(0);
8587 }
8588 
8589 #undef __FUNCT__
8590 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8591 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8592 {
8593   PetscSection       coordSection;
8594   Vec                coordinates;
8595   const PetscScalar *coords;
8596   const PetscInt     dim = 2;
8597   PetscInt           d, f;
8598   PetscErrorCode     ierr;
8599 
8600   PetscFunctionBegin;
8601   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8602   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8603   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8604   if (v0) {
8605     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8606   }
8607   if (J) {
8608     for (d = 0; d < dim; d++) {
8609       for (f = 0; f < dim; f++) {
8610         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8611       }
8612     }
8613     *detJ = J[0]*J[3] - J[1]*J[2];
8614 #if 0
8615     if (detJ < 0.0) {
8616       const PetscReal xLength = mesh->periodicity[0];
8617 
8618       if (xLength != 0.0) {
8619         PetscReal v0x = coords[0*dim+0];
8620 
8621         if (v0x == 0.0) v0x = v0[0] = xLength;
8622         for (f = 0; f < dim; f++) {
8623           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8624 
8625           J[0*dim+f] = 0.5*(px - v0x);
8626         }
8627       }
8628       detJ = J[0]*J[3] - J[1]*J[2];
8629     }
8630 #endif
8631     PetscLogFlops(8.0 + 3.0);
8632   }
8633   if (invJ) {
8634     const PetscReal invDet = 1.0/(*detJ);
8635 
8636     invJ[0] =  invDet*J[3];
8637     invJ[1] = -invDet*J[1];
8638     invJ[2] = -invDet*J[2];
8639     invJ[3] =  invDet*J[0];
8640     PetscLogFlops(5.0);
8641   }
8642   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8643   PetscFunctionReturn(0);
8644 }
8645 
8646 #undef __FUNCT__
8647 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8648 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8649 {
8650   PetscSection       coordSection;
8651   Vec                coordinates;
8652   const PetscScalar *coords;
8653   const PetscInt     dim = 2;
8654   PetscInt           d, f;
8655   PetscErrorCode     ierr;
8656 
8657   PetscFunctionBegin;
8658   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8659   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8660   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8661   if (v0) {
8662     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8663   }
8664   if (J) {
8665     for (d = 0; d < dim; d++) {
8666       for (f = 0; f < dim; f++) {
8667         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8668       }
8669     }
8670     *detJ = J[0]*J[3] - J[1]*J[2];
8671     PetscLogFlops(8.0 + 3.0);
8672   }
8673   if (invJ) {
8674     const PetscReal invDet = 1.0/(*detJ);
8675 
8676     invJ[0] =  invDet*J[3];
8677     invJ[1] = -invDet*J[1];
8678     invJ[2] = -invDet*J[2];
8679     invJ[3] =  invDet*J[0];
8680     PetscLogFlops(5.0);
8681   }
8682   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8683   PetscFunctionReturn(0);
8684 }
8685 
8686 #undef __FUNCT__
8687 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8688 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8689 {
8690   PetscSection       coordSection;
8691   Vec                coordinates;
8692   const PetscScalar *coords;
8693   const PetscInt     dim = 3;
8694   PetscInt           d, f;
8695   PetscErrorCode     ierr;
8696 
8697   PetscFunctionBegin;
8698   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8699   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8700   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8701   if (v0) {
8702     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8703   }
8704   if (J) {
8705     for (d = 0; d < dim; d++) {
8706       for (f = 0; f < dim; f++) {
8707         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8708       }
8709     }
8710     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8711     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8712              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8713              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8714     PetscLogFlops(18.0 + 12.0);
8715   }
8716   if (invJ) {
8717     const PetscReal invDet = 1.0/(*detJ);
8718 
8719     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8720     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8721     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8722     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8723     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8724     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8725     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8726     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8727     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8728     PetscLogFlops(37.0);
8729   }
8730   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8731   PetscFunctionReturn(0);
8732 }
8733 
8734 #undef __FUNCT__
8735 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8736 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8737 {
8738   PetscSection       coordSection;
8739   Vec                coordinates;
8740   const PetscScalar *coords;
8741   const PetscInt     dim = 3;
8742   PetscInt           d;
8743   PetscErrorCode     ierr;
8744 
8745   PetscFunctionBegin;
8746   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8747   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8748   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8749   if (v0) {
8750     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8751   }
8752   if (J) {
8753     for (d = 0; d < dim; d++) {
8754       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8755       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8756       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8757     }
8758     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8759              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8760              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8761     PetscLogFlops(18.0 + 12.0);
8762   }
8763   if (invJ) {
8764     const PetscReal invDet = -1.0/(*detJ);
8765 
8766     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8767     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8768     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8769     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8770     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8771     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8772     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8773     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8774     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8775     PetscLogFlops(37.0);
8776   }
8777   *detJ *= 8.0;
8778   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8779   PetscFunctionReturn(0);
8780 }
8781 
8782 #undef __FUNCT__
8783 #define __FUNCT__ "DMPlexComputeCellGeometry"
8784 /*@C
8785   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8786 
8787   Collective on DM
8788 
8789   Input Arguments:
8790 + dm   - the DM
8791 - cell - the cell
8792 
8793   Output Arguments:
8794 + v0   - the translation part of this affine transform
8795 . J    - the Jacobian of the transform to the reference element
8796 . invJ - the inverse of the Jacobian
8797 - detJ - the Jacobian determinant
8798 
8799   Level: advanced
8800 
8801 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8802 @*/
8803 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8804 {
8805   PetscInt       dim, coneSize;
8806   PetscErrorCode ierr;
8807 
8808   PetscFunctionBegin;
8809   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8810   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8811   switch (dim) {
8812   case 2:
8813     switch (coneSize) {
8814     case 3:
8815       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8816       break;
8817     case 4:
8818       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8819       break;
8820     default:
8821       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8822     }
8823     break;
8824   case 3:
8825     switch (coneSize) {
8826     case 4:
8827       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8828       break;
8829     case 8:
8830       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8831       break;
8832     default:
8833       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8834     }
8835     break;
8836   default:
8837     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8838   }
8839   PetscFunctionReturn(0);
8840 }
8841 
8842 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8843 {
8844   switch (i) {
8845   case 0:
8846     switch (j) {
8847     case 0: return 0;
8848     case 1:
8849       switch (k) {
8850       case 0: return 0;
8851       case 1: return 0;
8852       case 2: return 1;
8853       }
8854     case 2:
8855       switch (k) {
8856       case 0: return 0;
8857       case 1: return -1;
8858       case 2: return 0;
8859       }
8860     }
8861   case 1:
8862     switch (j) {
8863     case 0:
8864       switch (k) {
8865       case 0: return 0;
8866       case 1: return 0;
8867       case 2: return -1;
8868       }
8869     case 1: return 0;
8870     case 2:
8871       switch (k) {
8872       case 0: return 1;
8873       case 1: return 0;
8874       case 2: return 0;
8875       }
8876     }
8877   case 2:
8878     switch (j) {
8879     case 0:
8880       switch (k) {
8881       case 0: return 0;
8882       case 1: return 1;
8883       case 2: return 0;
8884       }
8885     case 1:
8886       switch (k) {
8887       case 0: return -1;
8888       case 1: return 0;
8889       case 2: return 0;
8890       }
8891     case 2: return 0;
8892     }
8893   }
8894   return 0;
8895 }
8896 
8897 #undef __FUNCT__
8898 #define __FUNCT__ "DMPlexCreateRigidBody"
8899 /*@C
8900   DMPlexCreateRigidBody - create rigid body modes from coordinates
8901 
8902   Collective on DM
8903 
8904   Input Arguments:
8905 + dm - the DM
8906 . section - the local section associated with the rigid field, or NULL for the default section
8907 - globalSection - the global section associated with the rigid field, or NULL for the default section
8908 
8909   Output Argument:
8910 . sp - the null space
8911 
8912   Note: This is necessary to take account of Dirichlet conditions on the displacements
8913 
8914   Level: advanced
8915 
8916 .seealso: MatNullSpaceCreate()
8917 @*/
8918 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8919 {
8920   MPI_Comm       comm;
8921   Vec            coordinates, localMode, mode[6];
8922   PetscSection   coordSection;
8923   PetscScalar   *coords;
8924   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8925   PetscErrorCode ierr;
8926 
8927   PetscFunctionBegin;
8928   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8929   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8930   if (dim == 1) {
8931     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8932     PetscFunctionReturn(0);
8933   }
8934   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8935   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8936   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8937   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8938   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8939   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8940   m    = (dim*(dim+1))/2;
8941   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8942   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8943   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8944   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8945   /* Assume P1 */
8946   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8947   for (d = 0; d < dim; ++d) {
8948     PetscScalar values[3] = {0.0, 0.0, 0.0};
8949 
8950     values[d] = 1.0;
8951     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8952     for (v = vStart; v < vEnd; ++v) {
8953       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8954     }
8955     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8956     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8957   }
8958   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8959   for (d = dim; d < dim*(dim+1)/2; ++d) {
8960     PetscInt i, j, k = dim > 2 ? d - dim : d;
8961 
8962     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8963     for (v = vStart; v < vEnd; ++v) {
8964       PetscScalar values[3] = {0.0, 0.0, 0.0};
8965       PetscInt    off;
8966 
8967       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8968       for (i = 0; i < dim; ++i) {
8969         for (j = 0; j < dim; ++j) {
8970           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8971         }
8972       }
8973       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8974     }
8975     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8976     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8977   }
8978   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8979   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8980   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
8981   /* Orthonormalize system */
8982   for (i = dim; i < m; ++i) {
8983     PetscScalar dots[6];
8984 
8985     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8986     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8987     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8988     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
8989   }
8990   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8991   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8992   PetscFunctionReturn(0);
8993 }
8994 
8995 #undef __FUNCT__
8996 #define __FUNCT__ "DMPlexGetHybridBounds"
8997 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
8998 {
8999   DM_Plex       *mesh = (DM_Plex*) dm->data;
9000   PetscInt       dim;
9001   PetscErrorCode ierr;
9002 
9003   PetscFunctionBegin;
9004   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9005   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9006   if (cMax) *cMax = mesh->hybridPointMax[dim];
9007   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9008   if (eMax) *eMax = mesh->hybridPointMax[1];
9009   if (vMax) *vMax = mesh->hybridPointMax[0];
9010   PetscFunctionReturn(0);
9011 }
9012 
9013 #undef __FUNCT__
9014 #define __FUNCT__ "DMPlexSetHybridBounds"
9015 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9016 {
9017   DM_Plex       *mesh = (DM_Plex*) dm->data;
9018   PetscInt       dim;
9019   PetscErrorCode ierr;
9020 
9021   PetscFunctionBegin;
9022   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9023   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9024   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9025   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9026   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9027   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9028   PetscFunctionReturn(0);
9029 }
9030 
9031 #undef __FUNCT__
9032 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9033 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9034 {
9035   DM_Plex *mesh = (DM_Plex*) dm->data;
9036 
9037   PetscFunctionBegin;
9038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9039   PetscValidPointer(cellHeight, 2);
9040   *cellHeight = mesh->vtkCellHeight;
9041   PetscFunctionReturn(0);
9042 }
9043 
9044 #undef __FUNCT__
9045 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9046 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9047 {
9048   DM_Plex *mesh = (DM_Plex*) dm->data;
9049 
9050   PetscFunctionBegin;
9051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9052   mesh->vtkCellHeight = cellHeight;
9053   PetscFunctionReturn(0);
9054 }
9055 
9056 #undef __FUNCT__
9057 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9058 /* We can easily have a form that takes an IS instead */
9059 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9060 {
9061   PetscSection   section, globalSection;
9062   PetscInt      *numbers, p;
9063   PetscErrorCode ierr;
9064 
9065   PetscFunctionBegin;
9066   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9067   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9068   for (p = pStart; p < pEnd; ++p) {
9069     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9070   }
9071   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9072   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9073   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9074   for (p = pStart; p < pEnd; ++p) {
9075     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9076   }
9077   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9078   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9079   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9080   PetscFunctionReturn(0);
9081 }
9082 
9083 #undef __FUNCT__
9084 #define __FUNCT__ "DMPlexGetCellNumbering"
9085 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9086 {
9087   DM_Plex       *mesh = (DM_Plex*) dm->data;
9088   PetscInt       cellHeight, cStart, cEnd, cMax;
9089   PetscErrorCode ierr;
9090 
9091   PetscFunctionBegin;
9092   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9093   if (!mesh->globalCellNumbers) {
9094     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9095     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9096     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9097     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9098     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9099   }
9100   *globalCellNumbers = mesh->globalCellNumbers;
9101   PetscFunctionReturn(0);
9102 }
9103 
9104 #undef __FUNCT__
9105 #define __FUNCT__ "DMPlexGetVertexNumbering"
9106 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9107 {
9108   DM_Plex       *mesh = (DM_Plex*) dm->data;
9109   PetscInt       vStart, vEnd, vMax;
9110   PetscErrorCode ierr;
9111 
9112   PetscFunctionBegin;
9113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9114   if (!mesh->globalVertexNumbers) {
9115     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9116     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9117     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9118     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9119   }
9120   *globalVertexNumbers = mesh->globalVertexNumbers;
9121   PetscFunctionReturn(0);
9122 }
9123 
9124 #undef __FUNCT__
9125 #define __FUNCT__ "DMPlexGetScale"
9126 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9127 {
9128   DM_Plex *mesh = (DM_Plex*) dm->data;
9129 
9130   PetscFunctionBegin;
9131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9132   PetscValidPointer(scale, 3);
9133   *scale = mesh->scale[unit];
9134   PetscFunctionReturn(0);
9135 }
9136 
9137 #undef __FUNCT__
9138 #define __FUNCT__ "DMPlexSetScale"
9139 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9140 {
9141   DM_Plex *mesh = (DM_Plex*) dm->data;
9142 
9143   PetscFunctionBegin;
9144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9145   mesh->scale[unit] = scale;
9146   PetscFunctionReturn(0);
9147 }
9148 
9149 
9150 /*******************************************************************************
9151 This should be in a separate Discretization object, but I am not sure how to lay
9152 it out yet, so I am stuffing things here while I experiment.
9153 *******************************************************************************/
9154 #undef __FUNCT__
9155 #define __FUNCT__ "DMPlexSetFEMIntegration"
9156 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9157                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9158                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9159                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9160                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9161                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9162                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9163                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9164                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9165                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9166                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9167                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9168                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9169                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9170                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9171                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9172                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9173 {
9174   DM_Plex *mesh = (DM_Plex*) dm->data;
9175 
9176   PetscFunctionBegin;
9177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9178   mesh->integrateResidualFEM       = integrateResidualFEM;
9179   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9180   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9181   PetscFunctionReturn(0);
9182 }
9183 
9184 #undef __FUNCT__
9185 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9186 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9187 {
9188   Vec            coordinates;
9189   PetscSection   section, cSection;
9190   PetscInt       dim, vStart, vEnd, v, c, d;
9191   PetscScalar   *values, *cArray;
9192   PetscReal     *coords;
9193   PetscErrorCode ierr;
9194 
9195   PetscFunctionBegin;
9196   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9197   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9198   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9199   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9200   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9201   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9202   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9203   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9204   for (v = vStart; v < vEnd; ++v) {
9205     PetscInt dof, off;
9206 
9207     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9208     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9209     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9210     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9211     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9212     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9213   }
9214   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9215   /* Temporary, must be replaced by a projection on the finite element basis */
9216   {
9217     PetscInt eStart = 0, eEnd = 0, e, depth;
9218 
9219     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9220     --depth;
9221     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9222     for (e = eStart; e < eEnd; ++e) {
9223       const PetscInt *cone = NULL;
9224       PetscInt        coneSize, d;
9225       PetscScalar    *coordsA, *coordsB;
9226 
9227       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9228       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9229       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9230       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9231       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9232       for (d = 0; d < dim; ++d) {
9233         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9234       }
9235       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9236       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9237     }
9238   }
9239 
9240   ierr = PetscFree(coords);CHKERRQ(ierr);
9241   ierr = PetscFree(values);CHKERRQ(ierr);
9242 #if 0
9243   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9244   PetscReal      detJ;
9245 
9246   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9247   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9248   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9249 
9250   for (PetscInt c = cStart; c < cEnd; ++c) {
9251     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9252     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9253     const int                          oSize   = pV.getSize();
9254     int                                v       = 0;
9255 
9256     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9257     for (PetscInt cl = 0; cl < oSize; ++cl) {
9258       const PetscInt fDim;
9259 
9260       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9261       if (pointDim) {
9262         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9263           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9264         }
9265       }
9266     }
9267     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9268     pV.clear();
9269   }
9270   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9271   ierr = PetscFree(values);CHKERRQ(ierr);
9272 #endif
9273   PetscFunctionReturn(0);
9274 }
9275 
9276 #undef __FUNCT__
9277 #define __FUNCT__ "DMPlexProjectFunction"
9278 /*@C
9279   DMPlexProjectFunction - This projects the given function into the function space provided.
9280 
9281   Input Parameters:
9282 + dm      - The DM
9283 . numComp - The number of components (functions)
9284 . funcs   - The coordinate functions to evaluate
9285 - mode    - The insertion mode for values
9286 
9287   Output Parameter:
9288 . X - vector
9289 
9290   Level: developer
9291 
9292   Note:
9293   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9294   We will eventually fix it.
9295 
9296 ,seealso: DMPlexComputeL2Diff()
9297 */
9298 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9299 {
9300   Vec            localX;
9301   PetscErrorCode ierr;
9302 
9303   PetscFunctionBegin;
9304   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9305   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9306   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9307   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9308   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9309   PetscFunctionReturn(0);
9310 }
9311 
9312 #undef __FUNCT__
9313 #define __FUNCT__ "DMPlexComputeL2Diff"
9314 /*@C
9315   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9316 
9317   Input Parameters:
9318 + dm    - The DM
9319 . quad  - The PetscQuadrature object for each field
9320 . funcs - The functions to evaluate for each field component
9321 - X     - The coefficient vector u_h
9322 
9323   Output Parameter:
9324 . diff - The diff ||u - u_h||_2
9325 
9326   Level: developer
9327 
9328 .seealso: DMPlexProjectFunction()
9329 */
9330 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9331 {
9332   const PetscInt debug = 0;
9333   PetscSection   section;
9334   Vec            localX;
9335   PetscReal     *coords, *v0, *J, *invJ, detJ;
9336   PetscReal      localDiff = 0.0;
9337   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9338   PetscErrorCode ierr;
9339 
9340   PetscFunctionBegin;
9341   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9342   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9343   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9344   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9345   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9346   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9347   for (field = 0; field < numFields; ++field) {
9348     numComponents += quad[field].numComponents;
9349   }
9350   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9351   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9352   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9353   for (c = cStart; c < cEnd; ++c) {
9354     const PetscScalar *x;
9355     PetscReal          elemDiff = 0.0;
9356 
9357     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9358     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9359     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9360 
9361     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9362       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9363       const PetscReal *quadPoints    = quad[field].quadPoints;
9364       const PetscReal *quadWeights   = quad[field].quadWeights;
9365       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9366       const PetscInt   numBasisComps = quad[field].numComponents;
9367       const PetscReal *basis         = quad[field].basis;
9368       PetscInt         q, d, e, fc, f;
9369 
9370       if (debug) {
9371         char title[1024];
9372         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9373         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9374       }
9375       for (q = 0; q < numQuadPoints; ++q) {
9376         for (d = 0; d < dim; d++) {
9377           coords[d] = v0[d];
9378           for (e = 0; e < dim; e++) {
9379             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9380           }
9381         }
9382         for (fc = 0; fc < numBasisComps; ++fc) {
9383           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9384           PetscReal       interpolant = 0.0;
9385           for (f = 0; f < numBasisFuncs; ++f) {
9386             const PetscInt fidx = f*numBasisComps+fc;
9387             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9388           }
9389           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9390           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9391         }
9392       }
9393       comp        += numBasisComps;
9394       fieldOffset += numBasisFuncs*numBasisComps;
9395     }
9396     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9397     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9398     localDiff += elemDiff;
9399   }
9400   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9401   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9402   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9403   *diff = PetscSqrtReal(*diff);
9404   PetscFunctionReturn(0);
9405 }
9406 
9407 #undef __FUNCT__
9408 #define __FUNCT__ "DMPlexComputeResidualFEM"
9409 /*@
9410   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9411 
9412   Input Parameters:
9413 + dm - The mesh
9414 . X  - Local input vector
9415 - user - The user context
9416 
9417   Output Parameter:
9418 . F  - Local output vector
9419 
9420   Note:
9421   The second member of the user context must be an FEMContext.
9422 
9423   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9424   like a GPU, or vectorize on a multicore machine.
9425 
9426 .seealso: DMPlexComputeJacobianActionFEM()
9427 */
9428 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9429 {
9430   DM_Plex         *mesh = (DM_Plex*) dm->data;
9431   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9432   PetscQuadrature *quad = fem->quad;
9433   PetscSection     section;
9434   PetscReal       *v0, *J, *invJ, *detJ;
9435   PetscScalar     *elemVec, *u;
9436   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9437   PetscInt         cellDof = 0, numComponents = 0;
9438   PetscErrorCode   ierr;
9439 
9440   PetscFunctionBegin;
9441   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9442   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9443   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9444   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9445   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9446   numCells = cEnd - cStart;
9447   for (field = 0; field < numFields; ++field) {
9448     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9449     numComponents += quad[field].numComponents;
9450   }
9451   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9452   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9453   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);
9454   for (c = cStart; c < cEnd; ++c) {
9455     const PetscScalar *x;
9456     PetscInt           i;
9457 
9458     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9459     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9460     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9461 
9462     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9463     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9464   }
9465   for (field = 0; field < numFields; ++field) {
9466     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9467     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9468     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9469     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9470     /* Conforming batches */
9471     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9472     PetscInt numBlocks  = 1;
9473     PetscInt batchSize  = numBlocks * blockSize;
9474     PetscInt numBatches = numBatchesTmp;
9475     PetscInt numChunks  = numCells / (numBatches*batchSize);
9476     /* Remainder */
9477     PetscInt numRemainder = numCells % (numBatches * batchSize);
9478     PetscInt offset       = numCells - numRemainder;
9479 
9480     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9481     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9482                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9483   }
9484   for (c = cStart; c < cEnd; ++c) {
9485     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9486     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9487   }
9488   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9489   if (mesh->printFEM) {
9490     PetscMPIInt rank, numProcs;
9491     PetscInt    p;
9492 
9493     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9494     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9495     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9496     for (p = 0; p < numProcs; ++p) {
9497       if (p == rank) {
9498         Vec f;
9499 
9500         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9501         ierr = VecCopy(F, f);CHKERRQ(ierr);
9502         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9503         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9504         ierr = VecDestroy(&f);CHKERRQ(ierr);
9505         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9506       }
9507       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9508     }
9509   }
9510   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9511   PetscFunctionReturn(0);
9512 }
9513 
9514 #undef __FUNCT__
9515 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9516 /*@C
9517   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9518 
9519   Input Parameters:
9520 + dm - The mesh
9521 . J  - The Jacobian shell matrix
9522 . X  - Local input vector
9523 - user - The user context
9524 
9525   Output Parameter:
9526 . F  - Local output vector
9527 
9528   Note:
9529   The second member of the user context must be an FEMContext.
9530 
9531   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9532   like a GPU, or vectorize on a multicore machine.
9533 
9534 .seealso: DMPlexComputeResidualFEM()
9535 */
9536 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9537 {
9538   DM_Plex         *mesh = (DM_Plex*) dm->data;
9539   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9540   PetscQuadrature *quad = fem->quad;
9541   PetscSection     section;
9542   JacActionCtx    *jctx;
9543   PetscReal       *v0, *J, *invJ, *detJ;
9544   PetscScalar     *elemVec, *u, *a;
9545   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9546   PetscInt         cellDof = 0;
9547   PetscErrorCode   ierr;
9548 
9549   PetscFunctionBegin;
9550   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9551   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9552   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9553   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9554   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9555   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9556   numCells = cEnd - cStart;
9557   for (field = 0; field < numFields; ++field) {
9558     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9559   }
9560   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9561   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);
9562   for (c = cStart; c < cEnd; ++c) {
9563     const PetscScalar *x;
9564     PetscInt           i;
9565 
9566     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9567     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9568     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9569     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9570     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9571     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9572     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9573     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9574   }
9575   for (field = 0; field < numFields; ++field) {
9576     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9577     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9578     /* Conforming batches */
9579     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9580     PetscInt numBlocks  = 1;
9581     PetscInt batchSize  = numBlocks * blockSize;
9582     PetscInt numBatches = numBatchesTmp;
9583     PetscInt numChunks  = numCells / (numBatches*batchSize);
9584     /* Remainder */
9585     PetscInt numRemainder = numCells % (numBatches * batchSize);
9586     PetscInt offset       = numCells - numRemainder;
9587 
9588     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);
9589     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],
9590                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9591   }
9592   for (c = cStart; c < cEnd; ++c) {
9593     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9594     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9595   }
9596   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9597   if (mesh->printFEM) {
9598     PetscMPIInt rank, numProcs;
9599     PetscInt    p;
9600 
9601     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9602     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9603     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9604     for (p = 0; p < numProcs; ++p) {
9605       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9606       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9607     }
9608   }
9609   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9610   PetscFunctionReturn(0);
9611 }
9612 
9613 #undef __FUNCT__
9614 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9615 /*@
9616   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9617 
9618   Input Parameters:
9619 + dm - The mesh
9620 . X  - Local input vector
9621 - user - The user context
9622 
9623   Output Parameter:
9624 . Jac  - Jacobian matrix
9625 
9626   Note:
9627   The second member of the user context must be an FEMContext.
9628 
9629   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9630   like a GPU, or vectorize on a multicore machine.
9631 
9632 .seealso: FormFunctionLocal()
9633 */
9634 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9635 {
9636   DM_Plex         *mesh = (DM_Plex*) dm->data;
9637   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9638   PetscQuadrature *quad = fem->quad;
9639   PetscSection     section;
9640   PetscReal       *v0, *J, *invJ, *detJ;
9641   PetscScalar     *elemMat, *u;
9642   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9643   PetscInt         cellDof = 0, numComponents = 0;
9644   PetscBool        isShell;
9645   PetscErrorCode   ierr;
9646 
9647   PetscFunctionBegin;
9648   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9649   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9650   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9651   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9652   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9653   numCells = cEnd - cStart;
9654   for (field = 0; field < numFields; ++field) {
9655     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9656     numComponents += quad[field].numComponents;
9657   }
9658   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9659   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9660   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);
9661   for (c = cStart; c < cEnd; ++c) {
9662     const PetscScalar *x;
9663     PetscInt           i;
9664 
9665     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9666     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9667     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9668 
9669     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9670     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9671   }
9672   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9673   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9674     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9675     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9676     PetscInt       fieldJ;
9677 
9678     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9679       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9680       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9681       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9682       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9683       /* Conforming batches */
9684       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9685       PetscInt numBlocks  = 1;
9686       PetscInt batchSize  = numBlocks * blockSize;
9687       PetscInt numBatches = numBatchesTmp;
9688       PetscInt numChunks  = numCells / (numBatches*batchSize);
9689       /* Remainder */
9690       PetscInt numRemainder = numCells % (numBatches * batchSize);
9691       PetscInt offset       = numCells - numRemainder;
9692 
9693       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9694       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9695                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9696     }
9697   }
9698   for (c = cStart; c < cEnd; ++c) {
9699     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9700     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9701   }
9702   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9703 
9704   /* Assemble matrix, using the 2-step process:
9705        MatAssemblyBegin(), MatAssemblyEnd(). */
9706   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9707   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9708 
9709   if (mesh->printFEM) {
9710     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9711     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9712     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9713   }
9714   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9715   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9716   if (isShell) {
9717     JacActionCtx *jctx;
9718 
9719     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9720     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9721   }
9722   *str = SAME_NONZERO_PATTERN;
9723   PetscFunctionReturn(0);
9724 }
9725 
9726 
9727 #undef __FUNCT__
9728 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9729 /*@C
9730   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9731   the local section and an SF describing the section point overlap.
9732 
9733   Input Parameters:
9734   + s - The PetscSection for the local field layout
9735   . sf - The SF describing parallel layout of the section points
9736   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9737   . label - The label specifying the points
9738   - labelValue - The label stratum specifying the points
9739 
9740   Output Parameter:
9741   . gsection - The PetscSection for the global field layout
9742 
9743   Note: This gives negative sizes and offsets to points not owned by this process
9744 
9745   Level: developer
9746 
9747 .seealso: PetscSectionCreate()
9748 @*/
9749 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9750 {
9751   PetscInt      *neg;
9752   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9753   PetscErrorCode ierr;
9754 
9755   PetscFunctionBegin;
9756   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9757   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9758   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9759   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9760   /* Mark ghost points with negative dof */
9761   for (p = pStart; p < pEnd; ++p) {
9762     PetscInt value;
9763 
9764     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9765     if (value != labelValue) continue;
9766     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9767     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9768     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9769     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9770     neg[p-pStart] = -(dof+1);
9771   }
9772   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9773   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9774   if (nroots >= 0) {
9775     if (nroots > pEnd - pStart) {
9776       PetscInt *tmpDof;
9777       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9778       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9779       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9780       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9781       for (p = pStart; p < pEnd; ++p) {
9782         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9783       }
9784       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9785     } else {
9786       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9787       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9788     }
9789   }
9790   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9791   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9792     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9793 
9794     (*gsection)->atlasOff[p] = off;
9795 
9796     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9797   }
9798   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9799   globalOff -= off;
9800   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9801     (*gsection)->atlasOff[p] += globalOff;
9802 
9803     neg[p] = -((*gsection)->atlasOff[p]+1);
9804   }
9805   /* Put in negative offsets for ghost points */
9806   if (nroots >= 0) {
9807     if (nroots > pEnd - pStart) {
9808       PetscInt *tmpOff;
9809       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9810       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9811       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9812       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9813       for (p = pStart; p < pEnd; ++p) {
9814         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9815       }
9816       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9817     } else {
9818       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9819       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9820     }
9821   }
9822   ierr = PetscFree(neg);CHKERRQ(ierr);
9823   PetscFunctionReturn(0);
9824 }
9825