xref: /petsc/src/dm/impls/plex/plex.c (revision 2f543b25c857ba60ed9b870dbfbc408af0170d29)
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       const PetscInt padj = tmpAdj[q];
548       PetscInt ndof, ncdof;
549 
550       if ((padj < pStart) || (padj >= pEnd)) continue;
551       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
552       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
553       for (d = off; d < off+dof; ++d) {
554         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
555       }
556     }
557   }
558   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
559   if (debug) {
560     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
561     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
562   }
563   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
564   if (size > 1) {
565     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
566     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
567   }
568   if (debug) {
569     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
570     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
571   }
572   /* Add in local adjacency sizes for owned dofs on interface (roots) */
573   for (p = pStart; p < pEnd; ++p) {
574     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
575 
576     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
577     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
578     if (!dof) continue;
579     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
580     if (adof <= 0) continue;
581     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
582     for (q = 0; q < numAdj; ++q) {
583       const PetscInt padj = tmpAdj[q];
584       PetscInt ndof, ncdof;
585 
586       if ((padj < pStart) || (padj >= pEnd)) continue;
587       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
588       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
589       for (d = off; d < off+dof; ++d) {
590         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
591       }
592     }
593   }
594   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
595   if (debug) {
596     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
597     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
598   }
599   /* Create adj SF based on dof SF */
600   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
601   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
602   if (debug) {
603     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
604     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
605   }
606   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
607   /* Create leaf adjacency */
608   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
609   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
610   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
611   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
612   for (l = 0; l < nleaves; ++l) {
613     PetscInt dof, off, d, q;
614     PetscInt p = leaves[l], numAdj = maxAdjSize;
615 
616     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
617     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
618     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
619     for (d = off; d < off+dof; ++d) {
620       PetscInt aoff, i = 0;
621 
622       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
623       for (q = 0; q < numAdj; ++q) {
624         const PetscInt padj = tmpAdj[q];
625         PetscInt ndof, ncdof, ngoff, nd;
626 
627         if ((padj < pStart) || (padj >= pEnd)) continue;
628         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
629         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
630         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
631         for (nd = 0; nd < ndof-ncdof; ++nd) {
632           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
633           ++i;
634         }
635       }
636     }
637   }
638   /* Debugging */
639   if (debug) {
640     IS tmp;
641     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
642     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
643     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
644   }
645   /* Gather adjacenct indices to root */
646   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
647   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
648   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
649   if (size > 1) {
650     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
651     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
652   }
653   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
654   ierr = PetscFree(adj);CHKERRQ(ierr);
655   /* Debugging */
656   if (debug) {
657     IS tmp;
658     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
659     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
660     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
661   }
662   /* Add in local adjacency indices for owned dofs on interface (roots) */
663   for (p = pStart; p < pEnd; ++p) {
664     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
665 
666     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
667     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
668     if (!dof) continue;
669     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
670     if (adof <= 0) continue;
671     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
672     for (d = off; d < off+dof; ++d) {
673       PetscInt adof, aoff, i;
674 
675       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
676       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
677       i    = adof-1;
678       for (q = 0; q < numAdj; ++q) {
679         const PetscInt padj = tmpAdj[q];
680         PetscInt ndof, ncdof, ngoff, nd;
681 
682         if ((padj < pStart) || (padj >= pEnd)) continue;
683         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
684         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
685         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
686         for (nd = 0; nd < ndof-ncdof; ++nd) {
687           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
688           --i;
689         }
690       }
691     }
692   }
693   /* Debugging */
694   if (debug) {
695     IS tmp;
696     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
697     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
698     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
699   }
700   /* Compress indices */
701   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
702   for (p = pStart; p < pEnd; ++p) {
703     PetscInt dof, cdof, off, d;
704     PetscInt adof, aoff;
705 
706     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
707     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
708     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
709     if (!dof) continue;
710     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
711     if (adof <= 0) continue;
712     for (d = off; d < off+dof-cdof; ++d) {
713       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
714       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
715       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
716       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
717     }
718   }
719   /* Debugging */
720   if (debug) {
721     IS tmp;
722     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
723     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
724     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
725     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
726     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
727   }
728   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
729   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
730   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
731   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
732   for (p = pStart; p < pEnd; ++p) {
733     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
734     PetscBool found  = PETSC_TRUE;
735 
736     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
737     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
738     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
739     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
740     for (d = 0; d < dof-cdof; ++d) {
741       PetscInt ldof, rdof;
742 
743       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
744       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
745       if (ldof > 0) {
746         /* We do not own this point */
747       } else if (rdof > 0) {
748         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
749       } else {
750         found = PETSC_FALSE;
751       }
752     }
753     if (found) continue;
754     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
755     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
756     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
757     for (q = 0; q < numAdj; ++q) {
758       const PetscInt padj = tmpAdj[q];
759       PetscInt ndof, ncdof, noff;
760 
761       if ((padj < pStart) || (padj >= pEnd)) continue;
762       ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
763       ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
764       ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr);
765       for (d = goff; d < goff+dof-cdof; ++d) {
766         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
767       }
768     }
769   }
770   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
771   if (debug) {
772     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
773     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
774   }
775   /* Get adjacent indices */
776   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
777   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
778   for (p = pStart; p < pEnd; ++p) {
779     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
780     PetscBool found  = PETSC_TRUE;
781 
782     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
783     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
784     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
785     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
786     for (d = 0; d < dof-cdof; ++d) {
787       PetscInt ldof, rdof;
788 
789       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
790       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
791       if (ldof > 0) {
792         /* We do not own this point */
793       } else if (rdof > 0) {
794         PetscInt aoff, roff;
795 
796         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
797         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
798         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
799       } else {
800         found = PETSC_FALSE;
801       }
802     }
803     if (found) continue;
804     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
805     for (d = goff; d < goff+dof-cdof; ++d) {
806       PetscInt adof, aoff, i = 0;
807 
808       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
809       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
810       for (q = 0; q < numAdj; ++q) {
811         const PetscInt  padj = tmpAdj[q];
812         PetscInt        ndof, ncdof, ngoff, nd;
813         const PetscInt *ncind;
814 
815         /* Adjacent points may not be in the section chart */
816         if ((padj < pStart) || (padj >= pEnd)) continue;
817         ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr);
818         ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr);
819         ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr);
820         ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr);
821         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
822           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
823         }
824       }
825       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);
826     }
827   }
828   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
829   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
830   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
831   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
832   /* Debugging */
833   if (debug) {
834     IS tmp;
835     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
836     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
837     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
838   }
839   /* Create allocation vectors from adjacency graph */
840   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
841   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
842   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
843   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
844   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
845   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
846   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
847   /* Only loop over blocks of rows */
848   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);
849   for (r = rStart/bs; r < rEnd/bs; ++r) {
850     const PetscInt row = r*bs;
851     PetscInt       numCols, cStart, c;
852 
853     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
854     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
855     for (c = cStart; c < cStart+numCols; ++c) {
856       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
857         ++dnz[r-rStart];
858         if (cols[c] >= row) ++dnzu[r-rStart];
859       } else {
860         ++onz[r-rStart];
861         if (cols[c] >= row) ++onzu[r-rStart];
862       }
863     }
864   }
865   if (bs > 1) {
866     for (r = 0; r < locRows/bs; ++r) {
867       dnz[r]  /= bs;
868       onz[r]  /= bs;
869       dnzu[r] /= bs;
870       onzu[r] /= bs;
871     }
872   }
873   /* Set matrix pattern */
874   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
875   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
876   /* Fill matrix with zeros */
877   if (fillMatrix) {
878     PetscScalar *values;
879     PetscInt     maxRowLen = 0;
880 
881     for (r = rStart; r < rEnd; ++r) {
882       PetscInt len;
883 
884       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
885       maxRowLen = PetscMax(maxRowLen, len);
886     }
887     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
888     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
889     for (r = rStart; r < rEnd; ++r) {
890       PetscInt numCols, cStart;
891 
892       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
893       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
894       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
895     }
896     ierr = PetscFree(values);CHKERRQ(ierr);
897     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
898     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
899   }
900   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
901   ierr = PetscFree(cols);CHKERRQ(ierr);
902   PetscFunctionReturn(0);
903 }
904 
905 #if 0
906 #undef __FUNCT__
907 #define __FUNCT__ "DMPlexPreallocateOperator_2"
908 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
909 {
910   PetscInt       *tmpClosure,*tmpAdj,*visits;
911   PetscInt        c,cStart,cEnd,pStart,pEnd;
912   PetscErrorCode  ierr;
913 
914   PetscFunctionBegin;
915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
918 
919   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
920 
921   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
922   npoints = pEnd - pStart;
923 
924   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
925   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
926   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
927   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
928   for (c=cStart; c<cEnd; c++) {
929     PetscInt *support = tmpClosure;
930     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
931     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
932   }
933   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
934   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
935   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
936   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
937 
938   ierr = PetscSFGetRanks();CHKERRQ(ierr);
939 
940 
941   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
942   for (c=cStart; c<cEnd; c++) {
943     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
944     /*
945      Depth-first walk of transitive closure.
946      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.
947      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
948      */
949   }
950 
951   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
952   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
953   PetscFunctionReturn(0);
954 }
955 #endif
956 
957 #undef __FUNCT__
958 #define __FUNCT__ "DMCreateMatrix_Plex"
959 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
960 {
961   PetscSection   section, sectionGlobal;
962   PetscInt       bs = -1;
963   PetscInt       localSize;
964   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
965   PetscErrorCode ierr;
966 
967   PetscFunctionBegin;
968 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
969   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
970 #endif
971   if (!mtype) mtype = MATAIJ;
972   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
973   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
974   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
975   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
976   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
977   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
978   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
979   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
980   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
981   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
982   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
983   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
984   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
985   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
986   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
987   /* Check for symmetric storage */
988   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
989   if (isSymmetric) {
990     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
991   }
992   if (!isShell) {
993     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
994     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
995 
996     if (bs < 0) {
997       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
998         PetscInt pStart, pEnd, p, dof, cdof;
999 
1000         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1001         for (p = pStart; p < pEnd; ++p) {
1002           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1003           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
1004           if (dof-cdof) {
1005             if (bs < 0) {
1006               bs = dof-cdof;
1007             } else if (bs != dof-cdof) {
1008               /* Layout does not admit a pointwise block size */
1009               bs = 1;
1010               break;
1011             }
1012           }
1013         }
1014         /* Must have same blocksize on all procs (some might have no points) */
1015         bsLocal = bs;
1016         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1017         bsLocal = bs < 0 ? bsMax : bs;
1018         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1019         if (bsMin != bsMax) {
1020           bs = 1;
1021         } else {
1022           bs = bsMax;
1023         }
1024       } else {
1025         bs = 1;
1026       }
1027     }
1028     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1029     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1030     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1031     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1032     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1033     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1034     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1035   }
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 #undef __FUNCT__
1040 #define __FUNCT__ "DMPlexGetDimension"
1041 /*@
1042   DMPlexGetDimension - Return the topological mesh dimension
1043 
1044   Not collective
1045 
1046   Input Parameter:
1047 . mesh - The DMPlex
1048 
1049   Output Parameter:
1050 . dim - The topological mesh dimension
1051 
1052   Level: beginner
1053 
1054 .seealso: DMPlexCreate()
1055 @*/
1056 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1057 {
1058   DM_Plex *mesh = (DM_Plex*) dm->data;
1059 
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1062   PetscValidPointer(dim, 2);
1063   *dim = mesh->dim;
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 #undef __FUNCT__
1068 #define __FUNCT__ "DMPlexSetDimension"
1069 /*@
1070   DMPlexSetDimension - Set the topological mesh dimension
1071 
1072   Collective on mesh
1073 
1074   Input Parameters:
1075 + mesh - The DMPlex
1076 - dim - The topological mesh dimension
1077 
1078   Level: beginner
1079 
1080 .seealso: DMPlexCreate()
1081 @*/
1082 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1083 {
1084   DM_Plex *mesh = (DM_Plex*) dm->data;
1085 
1086   PetscFunctionBegin;
1087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1088   PetscValidLogicalCollectiveInt(dm, dim, 2);
1089   mesh->dim               = dim;
1090   mesh->preallocCenterDim = dim;
1091   PetscFunctionReturn(0);
1092 }
1093 
1094 #undef __FUNCT__
1095 #define __FUNCT__ "DMPlexGetChart"
1096 /*@
1097   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1098 
1099   Not collective
1100 
1101   Input Parameter:
1102 . mesh - The DMPlex
1103 
1104   Output Parameters:
1105 + pStart - The first mesh point
1106 - pEnd   - The upper bound for mesh points
1107 
1108   Level: beginner
1109 
1110 .seealso: DMPlexCreate(), DMPlexSetChart()
1111 @*/
1112 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1113 {
1114   DM_Plex       *mesh = (DM_Plex*) dm->data;
1115   PetscErrorCode ierr;
1116 
1117   PetscFunctionBegin;
1118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1119   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1120   PetscFunctionReturn(0);
1121 }
1122 
1123 #undef __FUNCT__
1124 #define __FUNCT__ "DMPlexSetChart"
1125 /*@
1126   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1127 
1128   Not collective
1129 
1130   Input Parameters:
1131 + mesh - The DMPlex
1132 . pStart - The first mesh point
1133 - pEnd   - The upper bound for mesh points
1134 
1135   Output Parameters:
1136 
1137   Level: beginner
1138 
1139 .seealso: DMPlexCreate(), DMPlexGetChart()
1140 @*/
1141 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1142 {
1143   DM_Plex       *mesh = (DM_Plex*) dm->data;
1144   PetscErrorCode ierr;
1145 
1146   PetscFunctionBegin;
1147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1148   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1149   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 #undef __FUNCT__
1154 #define __FUNCT__ "DMPlexGetConeSize"
1155 /*@
1156   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1157 
1158   Not collective
1159 
1160   Input Parameters:
1161 + mesh - The DMPlex
1162 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1163 
1164   Output Parameter:
1165 . size - The cone size for point p
1166 
1167   Level: beginner
1168 
1169 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1170 @*/
1171 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1172 {
1173   DM_Plex       *mesh = (DM_Plex*) dm->data;
1174   PetscErrorCode ierr;
1175 
1176   PetscFunctionBegin;
1177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1178   PetscValidPointer(size, 3);
1179   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1180   PetscFunctionReturn(0);
1181 }
1182 
1183 #undef __FUNCT__
1184 #define __FUNCT__ "DMPlexSetConeSize"
1185 /*@
1186   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1187 
1188   Not collective
1189 
1190   Input Parameters:
1191 + mesh - The DMPlex
1192 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1193 - size - The cone size for point p
1194 
1195   Output Parameter:
1196 
1197   Note:
1198   This should be called after DMPlexSetChart().
1199 
1200   Level: beginner
1201 
1202 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1203 @*/
1204 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1205 {
1206   DM_Plex       *mesh = (DM_Plex*) dm->data;
1207   PetscErrorCode ierr;
1208 
1209   PetscFunctionBegin;
1210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1211   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1212 
1213   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1214   PetscFunctionReturn(0);
1215 }
1216 
1217 #undef __FUNCT__
1218 #define __FUNCT__ "DMPlexGetCone"
1219 /*@C
1220   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1221 
1222   Not collective
1223 
1224   Input Parameters:
1225 + mesh - The DMPlex
1226 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1227 
1228   Output Parameter:
1229 . cone - An array of points which are on the in-edges for point p
1230 
1231   Level: beginner
1232 
1233   Note:
1234   This routine is not available in Fortran.
1235 
1236 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1237 @*/
1238 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1239 {
1240   DM_Plex       *mesh = (DM_Plex*) dm->data;
1241   PetscInt       off;
1242   PetscErrorCode ierr;
1243 
1244   PetscFunctionBegin;
1245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1246   PetscValidPointer(cone, 3);
1247   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1248   *cone = &mesh->cones[off];
1249   PetscFunctionReturn(0);
1250 }
1251 
1252 #undef __FUNCT__
1253 #define __FUNCT__ "DMPlexSetCone"
1254 /*@
1255   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1256 
1257   Not collective
1258 
1259   Input Parameters:
1260 + mesh - The DMPlex
1261 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1262 - cone - An array of points which are on the in-edges for point p
1263 
1264   Output Parameter:
1265 
1266   Note:
1267   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1268 
1269   Level: beginner
1270 
1271 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1272 @*/
1273 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1274 {
1275   DM_Plex       *mesh = (DM_Plex*) dm->data;
1276   PetscInt       pStart, pEnd;
1277   PetscInt       dof, off, c;
1278   PetscErrorCode ierr;
1279 
1280   PetscFunctionBegin;
1281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1282   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1283   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1284   if (dof) PetscValidPointer(cone, 3);
1285   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1286   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);
1287   for (c = 0; c < dof; ++c) {
1288     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);
1289     mesh->cones[off+c] = cone[c];
1290   }
1291   PetscFunctionReturn(0);
1292 }
1293 
1294 #undef __FUNCT__
1295 #define __FUNCT__ "DMPlexGetConeOrientation"
1296 /*@C
1297   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1298 
1299   Not collective
1300 
1301   Input Parameters:
1302 + mesh - The DMPlex
1303 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1304 
1305   Output Parameter:
1306 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1307                     integer giving the prescription for cone traversal. If it is negative, the cone is
1308                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1309                     the index of the cone point on which to start.
1310 
1311   Level: beginner
1312 
1313   Note:
1314   This routine is not available in Fortran.
1315 
1316 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1317 @*/
1318 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1319 {
1320   DM_Plex       *mesh = (DM_Plex*) dm->data;
1321   PetscInt       off;
1322   PetscErrorCode ierr;
1323 
1324   PetscFunctionBegin;
1325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1326 #if defined(PETSC_USE_DEBUG)
1327   {
1328     PetscInt dof;
1329     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1330     if (dof) PetscValidPointer(coneOrientation, 3);
1331   }
1332 #endif
1333   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1334 
1335   *coneOrientation = &mesh->coneOrientations[off];
1336   PetscFunctionReturn(0);
1337 }
1338 
1339 #undef __FUNCT__
1340 #define __FUNCT__ "DMPlexSetConeOrientation"
1341 /*@
1342   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1343 
1344   Not collective
1345 
1346   Input Parameters:
1347 + mesh - The DMPlex
1348 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1349 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1350                     integer giving the prescription for cone traversal. If it is negative, the cone is
1351                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1352                     the index of the cone point on which to start.
1353 
1354   Output Parameter:
1355 
1356   Note:
1357   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1358 
1359   Level: beginner
1360 
1361 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1362 @*/
1363 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1364 {
1365   DM_Plex       *mesh = (DM_Plex*) dm->data;
1366   PetscInt       pStart, pEnd;
1367   PetscInt       dof, off, c;
1368   PetscErrorCode ierr;
1369 
1370   PetscFunctionBegin;
1371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1372   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1373   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1374   if (dof) PetscValidPointer(coneOrientation, 3);
1375   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1376   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);
1377   for (c = 0; c < dof; ++c) {
1378     PetscInt cdof, o = coneOrientation[c];
1379 
1380     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1381     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);
1382     mesh->coneOrientations[off+c] = o;
1383   }
1384   PetscFunctionReturn(0);
1385 }
1386 
1387 #undef __FUNCT__
1388 #define __FUNCT__ "DMPlexInsertCone"
1389 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1390 {
1391   DM_Plex       *mesh = (DM_Plex*) dm->data;
1392   PetscInt       pStart, pEnd;
1393   PetscInt       dof, off;
1394   PetscErrorCode ierr;
1395 
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1399   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);
1400   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);
1401   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1402   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1403   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1404   mesh->cones[off+conePos] = conePoint;
1405   PetscFunctionReturn(0);
1406 }
1407 
1408 #undef __FUNCT__
1409 #define __FUNCT__ "DMPlexInsertConeOrientation"
1410 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1411 {
1412   DM_Plex       *mesh = (DM_Plex*) dm->data;
1413   PetscInt       pStart, pEnd;
1414   PetscInt       dof, off;
1415   PetscErrorCode ierr;
1416 
1417   PetscFunctionBegin;
1418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1419   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1420   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);
1421   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1422   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1423   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1424   mesh->coneOrientations[off+conePos] = coneOrientation;
1425   PetscFunctionReturn(0);
1426 }
1427 
1428 #undef __FUNCT__
1429 #define __FUNCT__ "DMPlexGetSupportSize"
1430 /*@
1431   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1432 
1433   Not collective
1434 
1435   Input Parameters:
1436 + mesh - The DMPlex
1437 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1438 
1439   Output Parameter:
1440 . size - The support size for point p
1441 
1442   Level: beginner
1443 
1444 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1445 @*/
1446 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1447 {
1448   DM_Plex       *mesh = (DM_Plex*) dm->data;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1453   PetscValidPointer(size, 3);
1454   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1455   PetscFunctionReturn(0);
1456 }
1457 
1458 #undef __FUNCT__
1459 #define __FUNCT__ "DMPlexSetSupportSize"
1460 /*@
1461   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1462 
1463   Not collective
1464 
1465   Input Parameters:
1466 + mesh - The DMPlex
1467 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1468 - size - The support size for point p
1469 
1470   Output Parameter:
1471 
1472   Note:
1473   This should be called after DMPlexSetChart().
1474 
1475   Level: beginner
1476 
1477 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1478 @*/
1479 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1480 {
1481   DM_Plex       *mesh = (DM_Plex*) dm->data;
1482   PetscErrorCode ierr;
1483 
1484   PetscFunctionBegin;
1485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1486   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1487 
1488   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1489   PetscFunctionReturn(0);
1490 }
1491 
1492 #undef __FUNCT__
1493 #define __FUNCT__ "DMPlexGetSupport"
1494 /*@C
1495   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1496 
1497   Not collective
1498 
1499   Input Parameters:
1500 + mesh - The DMPlex
1501 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1502 
1503   Output Parameter:
1504 . support - An array of points which are on the out-edges for point p
1505 
1506   Level: beginner
1507 
1508 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1509 @*/
1510 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1511 {
1512   DM_Plex       *mesh = (DM_Plex*) dm->data;
1513   PetscInt       off;
1514   PetscErrorCode ierr;
1515 
1516   PetscFunctionBegin;
1517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1518   PetscValidPointer(support, 3);
1519   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1520   *support = &mesh->supports[off];
1521   PetscFunctionReturn(0);
1522 }
1523 
1524 #undef __FUNCT__
1525 #define __FUNCT__ "DMPlexSetSupport"
1526 /*@
1527   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1528 
1529   Not collective
1530 
1531   Input Parameters:
1532 + mesh - The DMPlex
1533 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1534 - support - An array of points which are on the in-edges for point p
1535 
1536   Output Parameter:
1537 
1538   Note:
1539   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1540 
1541   Level: beginner
1542 
1543 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1544 @*/
1545 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1546 {
1547   DM_Plex       *mesh = (DM_Plex*) dm->data;
1548   PetscInt       pStart, pEnd;
1549   PetscInt       dof, off, c;
1550   PetscErrorCode ierr;
1551 
1552   PetscFunctionBegin;
1553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1554   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1555   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1556   if (dof) PetscValidPointer(support, 3);
1557   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1558   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);
1559   for (c = 0; c < dof; ++c) {
1560     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);
1561     mesh->supports[off+c] = support[c];
1562   }
1563   PetscFunctionReturn(0);
1564 }
1565 
1566 #undef __FUNCT__
1567 #define __FUNCT__ "DMPlexInsertSupport"
1568 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1569 {
1570   DM_Plex       *mesh = (DM_Plex*) dm->data;
1571   PetscInt       pStart, pEnd;
1572   PetscInt       dof, off;
1573   PetscErrorCode ierr;
1574 
1575   PetscFunctionBegin;
1576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1577   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1578   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1579   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1580   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);
1581   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);
1582   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);
1583   mesh->supports[off+supportPos] = supportPoint;
1584   PetscFunctionReturn(0);
1585 }
1586 
1587 #undef __FUNCT__
1588 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1589 /*@C
1590   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1591 
1592   Not collective
1593 
1594   Input Parameters:
1595 + mesh - The DMPlex
1596 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1597 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1598 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1599 
1600   Output Parameters:
1601 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1602 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1603 
1604   Note:
1605   If using internal storage (points is NULL on input), each call overwrites the last output.
1606 
1607   Level: beginner
1608 
1609 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1610 @*/
1611 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1612 {
1613   DM_Plex        *mesh = (DM_Plex*) dm->data;
1614   PetscInt       *closure, *fifo;
1615   const PetscInt *tmp = NULL, *tmpO = NULL;
1616   PetscInt        tmpSize, t;
1617   PetscInt        depth       = 0, maxSize;
1618   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1619   PetscErrorCode  ierr;
1620 
1621   PetscFunctionBegin;
1622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1623   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1624   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1625   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1626   if (*points) {
1627     closure = *points;
1628   } else {
1629     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1630   }
1631   closure[0] = p; closure[1] = 0;
1632   /* This is only 1-level */
1633   if (useCone) {
1634     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1635     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1636     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1637   } else {
1638     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1639     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1640   }
1641   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1642     const PetscInt cp = tmp[t];
1643     const PetscInt co = tmpO ? tmpO[t] : 0;
1644 
1645     closure[closureSize]   = cp;
1646     closure[closureSize+1] = co;
1647     fifo[fifoSize]         = cp;
1648     fifo[fifoSize+1]       = co;
1649   }
1650   while (fifoSize - fifoStart) {
1651     const PetscInt q   = fifo[fifoStart];
1652     const PetscInt o   = fifo[fifoStart+1];
1653     const PetscInt rev = o >= 0 ? 0 : 1;
1654     const PetscInt off = rev ? -(o+1) : o;
1655 
1656     if (useCone) {
1657       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1658       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1659       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1660     } else {
1661       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1662       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1663       tmpO = NULL;
1664     }
1665     for (t = 0; t < tmpSize; ++t) {
1666       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1667       const PetscInt cp = tmp[i];
1668       /* Must propogate orientation */
1669       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1670       PetscInt       c;
1671 
1672       /* Check for duplicate */
1673       for (c = 0; c < closureSize; c += 2) {
1674         if (closure[c] == cp) break;
1675       }
1676       if (c == closureSize) {
1677         closure[closureSize]   = cp;
1678         closure[closureSize+1] = co;
1679         fifo[fifoSize]         = cp;
1680         fifo[fifoSize+1]       = co;
1681         closureSize           += 2;
1682         fifoSize              += 2;
1683       }
1684     }
1685     fifoStart += 2;
1686   }
1687   if (numPoints) *numPoints = closureSize/2;
1688   if (points)    *points    = closure;
1689   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1690   PetscFunctionReturn(0);
1691 }
1692 
1693 #undef __FUNCT__
1694 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1695 /*@C
1696   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1697 
1698   Not collective
1699 
1700   Input Parameters:
1701 + mesh - The DMPlex
1702 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1703 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1704 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1705 
1706   Output Parameters:
1707 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1708 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1709 
1710   Note:
1711   If not using internal storage (points is not NULL on input), this call is unnecessary
1712 
1713   Level: beginner
1714 
1715 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1716 @*/
1717 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1718 {
1719   PetscErrorCode ierr;
1720 
1721   PetscFunctionBegin;
1722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1723   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1724   PetscFunctionReturn(0);
1725 }
1726 
1727 #undef __FUNCT__
1728 #define __FUNCT__ "DMPlexGetMaxSizes"
1729 /*@
1730   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1731 
1732   Not collective
1733 
1734   Input Parameter:
1735 . mesh - The DMPlex
1736 
1737   Output Parameters:
1738 + maxConeSize - The maximum number of in-edges
1739 - maxSupportSize - The maximum number of out-edges
1740 
1741   Level: beginner
1742 
1743 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1744 @*/
1745 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1746 {
1747   DM_Plex *mesh = (DM_Plex*) dm->data;
1748 
1749   PetscFunctionBegin;
1750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1751   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1752   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1753   PetscFunctionReturn(0);
1754 }
1755 
1756 #undef __FUNCT__
1757 #define __FUNCT__ "DMSetUp_Plex"
1758 PetscErrorCode DMSetUp_Plex(DM dm)
1759 {
1760   DM_Plex       *mesh = (DM_Plex*) dm->data;
1761   PetscInt       size;
1762   PetscErrorCode ierr;
1763 
1764   PetscFunctionBegin;
1765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1766   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1767   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1768   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1769   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1770   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1771   if (mesh->maxSupportSize) {
1772     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1773     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1774     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1775   }
1776   PetscFunctionReturn(0);
1777 }
1778 
1779 #undef __FUNCT__
1780 #define __FUNCT__ "DMCreateSubDM_Plex"
1781 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1782 {
1783   PetscSection   section, sectionGlobal;
1784   PetscInt      *subIndices;
1785   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1786   PetscErrorCode ierr;
1787 
1788   PetscFunctionBegin;
1789   if (!numFields) PetscFunctionReturn(0);
1790   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1791   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1792   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1793   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1794   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1795   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);
1796   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1797   for (p = pStart; p < pEnd; ++p) {
1798     PetscInt gdof;
1799 
1800     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1801     if (gdof > 0) {
1802       for (f = 0; f < numFields; ++f) {
1803         PetscInt fdof, fcdof;
1804 
1805         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1806         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1807         subSize += fdof-fcdof;
1808       }
1809     }
1810   }
1811   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1812   for (p = pStart; p < pEnd; ++p) {
1813     PetscInt gdof, goff;
1814 
1815     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1816     if (gdof > 0) {
1817       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1818       for (f = 0; f < numFields; ++f) {
1819         PetscInt fdof, fcdof, fc, f2, poff = 0;
1820 
1821         /* Can get rid of this loop by storing field information in the global section */
1822         for (f2 = 0; f2 < fields[f]; ++f2) {
1823           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1824           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1825           poff += fdof-fcdof;
1826         }
1827         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1828         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1829         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1830           subIndices[subOff] = goff+poff+fc;
1831         }
1832       }
1833     }
1834   }
1835   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1836   if (subdm) {
1837     PetscSection subsection;
1838     PetscBool    haveNull = PETSC_FALSE;
1839     PetscInt     f, nf = 0;
1840 
1841     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1842     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1843     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1844     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1845     for (f = 0; f < numFields; ++f) {
1846       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1847       if ((*subdm)->nullspaceConstructors[f]) {
1848         haveNull = PETSC_TRUE;
1849         nf       = f;
1850       }
1851     }
1852     if (haveNull) {
1853       MatNullSpace nullSpace;
1854 
1855       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1856       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1857       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1858     }
1859     if (dm->fields) {
1860       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);
1861       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1862       for (f = 0; f < numFields; ++f) {
1863         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1864       }
1865       if (numFields == 1) {
1866         MatNullSpace space;
1867         Mat          pmat;
1868 
1869         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1870         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1871         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1872         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1873         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1874         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1875       }
1876     }
1877   }
1878   PetscFunctionReturn(0);
1879 }
1880 
1881 #undef __FUNCT__
1882 #define __FUNCT__ "DMPlexSymmetrize"
1883 /*@
1884   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1885 
1886   Not collective
1887 
1888   Input Parameter:
1889 . mesh - The DMPlex
1890 
1891   Output Parameter:
1892 
1893   Note:
1894   This should be called after all calls to DMPlexSetCone()
1895 
1896   Level: beginner
1897 
1898 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1899 @*/
1900 PetscErrorCode DMPlexSymmetrize(DM dm)
1901 {
1902   DM_Plex       *mesh = (DM_Plex*) dm->data;
1903   PetscInt      *offsets;
1904   PetscInt       supportSize;
1905   PetscInt       pStart, pEnd, p;
1906   PetscErrorCode ierr;
1907 
1908   PetscFunctionBegin;
1909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1910   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1911   /* Calculate support sizes */
1912   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1913   for (p = pStart; p < pEnd; ++p) {
1914     PetscInt dof, off, c;
1915 
1916     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1917     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1918     for (c = off; c < off+dof; ++c) {
1919       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1920     }
1921   }
1922   for (p = pStart; p < pEnd; ++p) {
1923     PetscInt dof;
1924 
1925     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1926 
1927     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1928   }
1929   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1930   /* Calculate supports */
1931   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1932   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1933   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1934   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1935   for (p = pStart; p < pEnd; ++p) {
1936     PetscInt dof, off, c;
1937 
1938     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1939     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1940     for (c = off; c < off+dof; ++c) {
1941       const PetscInt q = mesh->cones[c];
1942       PetscInt       offS;
1943 
1944       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1945 
1946       mesh->supports[offS+offsets[q]] = p;
1947       ++offsets[q];
1948     }
1949   }
1950   ierr = PetscFree(offsets);CHKERRQ(ierr);
1951   PetscFunctionReturn(0);
1952 }
1953 
1954 #undef __FUNCT__
1955 #define __FUNCT__ "DMPlexSetDepth_Private"
1956 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1957 {
1958   PetscInt       d;
1959   PetscErrorCode ierr;
1960 
1961   PetscFunctionBegin;
1962   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1963   if (d < 0) {
1964     /* We are guaranteed that the point has a cone since the depth was not yet set */
1965     const PetscInt *cone = NULL;
1966     PetscInt        dCone;
1967 
1968     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1969     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1970     d    = dCone+1;
1971     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1972   }
1973   *depth = d;
1974   PetscFunctionReturn(0);
1975 }
1976 
1977 #undef __FUNCT__
1978 #define __FUNCT__ "DMPlexStratify"
1979 /*@
1980   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1981   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1982   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1983   the DAG.
1984 
1985   Not collective
1986 
1987   Input Parameter:
1988 . mesh - The DMPlex
1989 
1990   Output Parameter:
1991 
1992   Notes:
1993   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1994   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1995 
1996   This should be called after all calls to DMPlexSymmetrize()
1997 
1998   Level: beginner
1999 
2000 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2001 @*/
2002 PetscErrorCode DMPlexStratify(DM dm)
2003 {
2004   DM_Plex       *mesh = (DM_Plex*) dm->data;
2005   PetscInt       pStart, pEnd, p;
2006   PetscInt       numRoots = 0, numLeaves = 0;
2007   PetscErrorCode ierr;
2008 
2009   PetscFunctionBegin;
2010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2011   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2012   /* Calculate depth */
2013   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2014   /* Initialize roots and count leaves */
2015   for (p = pStart; p < pEnd; ++p) {
2016     PetscInt coneSize, supportSize;
2017 
2018     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2019     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2020     if (!coneSize && supportSize) {
2021       ++numRoots;
2022       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2023     } else if (!supportSize && coneSize) {
2024       ++numLeaves;
2025     } else if (!supportSize && !coneSize) {
2026       /* Isolated points */
2027       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2028     }
2029   }
2030   if (numRoots + numLeaves == (pEnd - pStart)) {
2031     for (p = pStart; p < pEnd; ++p) {
2032       PetscInt coneSize, supportSize;
2033 
2034       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2035       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2036       if (!supportSize && coneSize) {
2037         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2038       }
2039     }
2040   } else {
2041     /* This might be slow since lookup is not fast */
2042     for (p = pStart; p < pEnd; ++p) {
2043       PetscInt depth;
2044 
2045       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2046     }
2047   }
2048   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2049   PetscFunctionReturn(0);
2050 }
2051 
2052 #undef __FUNCT__
2053 #define __FUNCT__ "DMPlexGetJoin"
2054 /*@C
2055   DMPlexGetJoin - Get an array for the join of the set of points
2056 
2057   Not Collective
2058 
2059   Input Parameters:
2060 + dm - The DMPlex object
2061 . numPoints - The number of input points for the join
2062 - points - The input points
2063 
2064   Output Parameters:
2065 + numCoveredPoints - The number of points in the join
2066 - coveredPoints - The points in the join
2067 
2068   Level: intermediate
2069 
2070   Note: Currently, this is restricted to a single level join
2071 
2072 .keywords: mesh
2073 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2074 @*/
2075 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2076 {
2077   DM_Plex       *mesh = (DM_Plex*) dm->data;
2078   PetscInt      *join[2];
2079   PetscInt       joinSize, i = 0;
2080   PetscInt       dof, off, p, c, m;
2081   PetscErrorCode ierr;
2082 
2083   PetscFunctionBegin;
2084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2085   PetscValidPointer(points, 2);
2086   PetscValidPointer(numCoveredPoints, 3);
2087   PetscValidPointer(coveredPoints, 4);
2088   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2089   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2090   /* Copy in support of first point */
2091   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2092   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2093   for (joinSize = 0; joinSize < dof; ++joinSize) {
2094     join[i][joinSize] = mesh->supports[off+joinSize];
2095   }
2096   /* Check each successive support */
2097   for (p = 1; p < numPoints; ++p) {
2098     PetscInt newJoinSize = 0;
2099 
2100     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2101     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2102     for (c = 0; c < dof; ++c) {
2103       const PetscInt point = mesh->supports[off+c];
2104 
2105       for (m = 0; m < joinSize; ++m) {
2106         if (point == join[i][m]) {
2107           join[1-i][newJoinSize++] = point;
2108           break;
2109         }
2110       }
2111     }
2112     joinSize = newJoinSize;
2113     i        = 1-i;
2114   }
2115   *numCoveredPoints = joinSize;
2116   *coveredPoints    = join[i];
2117   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2118   PetscFunctionReturn(0);
2119 }
2120 
2121 #undef __FUNCT__
2122 #define __FUNCT__ "DMPlexRestoreJoin"
2123 /*@C
2124   DMPlexRestoreJoin - Restore an array for the join of the set of points
2125 
2126   Not Collective
2127 
2128   Input Parameters:
2129 + dm - The DMPlex object
2130 . numPoints - The number of input points for the join
2131 - points - The input points
2132 
2133   Output Parameters:
2134 + numCoveredPoints - The number of points in the join
2135 - coveredPoints - The points in the join
2136 
2137   Level: intermediate
2138 
2139 .keywords: mesh
2140 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2141 @*/
2142 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2143 {
2144   PetscErrorCode ierr;
2145 
2146   PetscFunctionBegin;
2147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2148   PetscValidPointer(coveredPoints, 4);
2149   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMPlexGetFullJoin"
2155 /*@C
2156   DMPlexGetFullJoin - Get an array for the join of the set of points
2157 
2158   Not Collective
2159 
2160   Input Parameters:
2161 + dm - The DMPlex object
2162 . numPoints - The number of input points for the join
2163 - points - The input points
2164 
2165   Output Parameters:
2166 + numCoveredPoints - The number of points in the join
2167 - coveredPoints - The points in the join
2168 
2169   Level: intermediate
2170 
2171 .keywords: mesh
2172 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2173 @*/
2174 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2175 {
2176   DM_Plex       *mesh = (DM_Plex*) dm->data;
2177   PetscInt      *offsets, **closures;
2178   PetscInt      *join[2];
2179   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2180   PetscInt       p, d, c, m;
2181   PetscErrorCode ierr;
2182 
2183   PetscFunctionBegin;
2184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2185   PetscValidPointer(points, 2);
2186   PetscValidPointer(numCoveredPoints, 3);
2187   PetscValidPointer(coveredPoints, 4);
2188 
2189   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2190   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2191   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2192   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2193   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2194   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2195   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2196 
2197   for (p = 0; p < numPoints; ++p) {
2198     PetscInt closureSize;
2199 
2200     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2201 
2202     offsets[p*(depth+2)+0] = 0;
2203     for (d = 0; d < depth+1; ++d) {
2204       PetscInt pStart, pEnd, i;
2205 
2206       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2207       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2208         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2209           offsets[p*(depth+2)+d+1] = i;
2210           break;
2211         }
2212       }
2213       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2214     }
2215     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);
2216   }
2217   for (d = 0; d < depth+1; ++d) {
2218     PetscInt dof;
2219 
2220     /* Copy in support of first point */
2221     dof = offsets[d+1] - offsets[d];
2222     for (joinSize = 0; joinSize < dof; ++joinSize) {
2223       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2224     }
2225     /* Check each successive cone */
2226     for (p = 1; p < numPoints && joinSize; ++p) {
2227       PetscInt newJoinSize = 0;
2228 
2229       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2230       for (c = 0; c < dof; ++c) {
2231         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2232 
2233         for (m = 0; m < joinSize; ++m) {
2234           if (point == join[i][m]) {
2235             join[1-i][newJoinSize++] = point;
2236             break;
2237           }
2238         }
2239       }
2240       joinSize = newJoinSize;
2241       i        = 1-i;
2242     }
2243     if (joinSize) break;
2244   }
2245   *numCoveredPoints = joinSize;
2246   *coveredPoints    = join[i];
2247   for (p = 0; p < numPoints; ++p) {
2248     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2249   }
2250   ierr = PetscFree(closures);CHKERRQ(ierr);
2251   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2252   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2253   PetscFunctionReturn(0);
2254 }
2255 
2256 #undef __FUNCT__
2257 #define __FUNCT__ "DMPlexGetMeet"
2258 /*@C
2259   DMPlexGetMeet - Get an array for the meet of the set of points
2260 
2261   Not Collective
2262 
2263   Input Parameters:
2264 + dm - The DMPlex object
2265 . numPoints - The number of input points for the meet
2266 - points - The input points
2267 
2268   Output Parameters:
2269 + numCoveredPoints - The number of points in the meet
2270 - coveredPoints - The points in the meet
2271 
2272   Level: intermediate
2273 
2274   Note: Currently, this is restricted to a single level meet
2275 
2276 .keywords: mesh
2277 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2278 @*/
2279 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2280 {
2281   DM_Plex       *mesh = (DM_Plex*) dm->data;
2282   PetscInt      *meet[2];
2283   PetscInt       meetSize, i = 0;
2284   PetscInt       dof, off, p, c, m;
2285   PetscErrorCode ierr;
2286 
2287   PetscFunctionBegin;
2288   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2289   PetscValidPointer(points, 2);
2290   PetscValidPointer(numCoveringPoints, 3);
2291   PetscValidPointer(coveringPoints, 4);
2292   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2293   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2294   /* Copy in cone of first point */
2295   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2296   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2297   for (meetSize = 0; meetSize < dof; ++meetSize) {
2298     meet[i][meetSize] = mesh->cones[off+meetSize];
2299   }
2300   /* Check each successive cone */
2301   for (p = 1; p < numPoints; ++p) {
2302     PetscInt newMeetSize = 0;
2303 
2304     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2305     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2306     for (c = 0; c < dof; ++c) {
2307       const PetscInt point = mesh->cones[off+c];
2308 
2309       for (m = 0; m < meetSize; ++m) {
2310         if (point == meet[i][m]) {
2311           meet[1-i][newMeetSize++] = point;
2312           break;
2313         }
2314       }
2315     }
2316     meetSize = newMeetSize;
2317     i        = 1-i;
2318   }
2319   *numCoveringPoints = meetSize;
2320   *coveringPoints    = meet[i];
2321   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2322   PetscFunctionReturn(0);
2323 }
2324 
2325 #undef __FUNCT__
2326 #define __FUNCT__ "DMPlexRestoreMeet"
2327 /*@C
2328   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2329 
2330   Not Collective
2331 
2332   Input Parameters:
2333 + dm - The DMPlex object
2334 . numPoints - The number of input points for the meet
2335 - points - The input points
2336 
2337   Output Parameters:
2338 + numCoveredPoints - The number of points in the meet
2339 - coveredPoints - The points in the meet
2340 
2341   Level: intermediate
2342 
2343 .keywords: mesh
2344 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2345 @*/
2346 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2347 {
2348   PetscErrorCode ierr;
2349 
2350   PetscFunctionBegin;
2351   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2352   PetscValidPointer(coveredPoints, 4);
2353   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2354   PetscFunctionReturn(0);
2355 }
2356 
2357 #undef __FUNCT__
2358 #define __FUNCT__ "DMPlexGetFullMeet"
2359 /*@C
2360   DMPlexGetFullMeet - Get an array for the meet of the set of points
2361 
2362   Not Collective
2363 
2364   Input Parameters:
2365 + dm - The DMPlex object
2366 . numPoints - The number of input points for the meet
2367 - points - The input points
2368 
2369   Output Parameters:
2370 + numCoveredPoints - The number of points in the meet
2371 - coveredPoints - The points in the meet
2372 
2373   Level: intermediate
2374 
2375 .keywords: mesh
2376 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2377 @*/
2378 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2379 {
2380   DM_Plex       *mesh = (DM_Plex*) dm->data;
2381   PetscInt      *offsets, **closures;
2382   PetscInt      *meet[2];
2383   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2384   PetscInt       p, h, c, m;
2385   PetscErrorCode ierr;
2386 
2387   PetscFunctionBegin;
2388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2389   PetscValidPointer(points, 2);
2390   PetscValidPointer(numCoveredPoints, 3);
2391   PetscValidPointer(coveredPoints, 4);
2392 
2393   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2394   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2395   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2396   maxSize = PetscPowInt(mesh->maxConeSize,height);
2397   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2398   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2399 
2400   for (p = 0; p < numPoints; ++p) {
2401     PetscInt closureSize;
2402 
2403     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2404 
2405     offsets[p*(height+2)+0] = 0;
2406     for (h = 0; h < height+1; ++h) {
2407       PetscInt pStart, pEnd, i;
2408 
2409       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2410       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2411         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2412           offsets[p*(height+2)+h+1] = i;
2413           break;
2414         }
2415       }
2416       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2417     }
2418     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);
2419   }
2420   for (h = 0; h < height+1; ++h) {
2421     PetscInt dof;
2422 
2423     /* Copy in cone of first point */
2424     dof = offsets[h+1] - offsets[h];
2425     for (meetSize = 0; meetSize < dof; ++meetSize) {
2426       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2427     }
2428     /* Check each successive cone */
2429     for (p = 1; p < numPoints && meetSize; ++p) {
2430       PetscInt newMeetSize = 0;
2431 
2432       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2433       for (c = 0; c < dof; ++c) {
2434         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2435 
2436         for (m = 0; m < meetSize; ++m) {
2437           if (point == meet[i][m]) {
2438             meet[1-i][newMeetSize++] = point;
2439             break;
2440           }
2441         }
2442       }
2443       meetSize = newMeetSize;
2444       i        = 1-i;
2445     }
2446     if (meetSize) break;
2447   }
2448   *numCoveredPoints = meetSize;
2449   *coveredPoints    = meet[i];
2450   for (p = 0; p < numPoints; ++p) {
2451     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2452   }
2453   ierr = PetscFree(closures);CHKERRQ(ierr);
2454   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2455   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2456   PetscFunctionReturn(0);
2457 }
2458 
2459 #undef __FUNCT__
2460 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2461 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2462 {
2463   MPI_Comm       comm;
2464   PetscErrorCode ierr;
2465 
2466   PetscFunctionBegin;
2467   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2468   PetscValidPointer(numFaceVertices,3);
2469   switch (cellDim) {
2470   case 0:
2471     *numFaceVertices = 0;
2472     break;
2473   case 1:
2474     *numFaceVertices = 1;
2475     break;
2476   case 2:
2477     switch (numCorners) {
2478     case 3: /* triangle */
2479       *numFaceVertices = 2; /* Edge has 2 vertices */
2480       break;
2481     case 4: /* quadrilateral */
2482       *numFaceVertices = 2; /* Edge has 2 vertices */
2483       break;
2484     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2485       *numFaceVertices = 3; /* Edge has 3 vertices */
2486       break;
2487     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2488       *numFaceVertices = 3; /* Edge has 3 vertices */
2489       break;
2490     default:
2491       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2492     }
2493     break;
2494   case 3:
2495     switch (numCorners) {
2496     case 4: /* tetradehdron */
2497       *numFaceVertices = 3; /* Face has 3 vertices */
2498       break;
2499     case 6: /* tet cohesive cells */
2500       *numFaceVertices = 4; /* Face has 4 vertices */
2501       break;
2502     case 8: /* hexahedron */
2503       *numFaceVertices = 4; /* Face has 4 vertices */
2504       break;
2505     case 9: /* tet cohesive Lagrange cells */
2506       *numFaceVertices = 6; /* Face has 6 vertices */
2507       break;
2508     case 10: /* quadratic tetrahedron */
2509       *numFaceVertices = 6; /* Face has 6 vertices */
2510       break;
2511     case 12: /* hex cohesive Lagrange cells */
2512       *numFaceVertices = 6; /* Face has 6 vertices */
2513       break;
2514     case 18: /* quadratic tet cohesive Lagrange cells */
2515       *numFaceVertices = 6; /* Face has 6 vertices */
2516       break;
2517     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2518       *numFaceVertices = 9; /* Face has 9 vertices */
2519       break;
2520     default:
2521       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2522     }
2523     break;
2524   default:
2525     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2526   }
2527   PetscFunctionReturn(0);
2528 }
2529 
2530 #undef __FUNCT__
2531 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2532 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2533 {
2534   const PetscInt maxFaceCases = 30;
2535   PetscInt       numFaceCases = 0;
2536   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2537   PetscInt      *off, *adj;
2538   PetscInt      *neighborCells, *tmpClosure;
2539   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2540   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2541   PetscErrorCode ierr;
2542 
2543   PetscFunctionBegin;
2544   /* For parallel partitioning, I think you have to communicate supports */
2545   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2546   cellDim = dim - cellHeight;
2547   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2548   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2549   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2550   if (cEnd - cStart == 0) {
2551     if (numVertices) *numVertices = 0;
2552     if (offsets)   *offsets   = NULL;
2553     if (adjacency) *adjacency = NULL;
2554     PetscFunctionReturn(0);
2555   }
2556   numCells  = cEnd - cStart;
2557   faceDepth = depth - cellHeight;
2558   /* Setup face recognition */
2559   if (faceDepth == 1) {
2560     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 */
2561 
2562     for (c = cStart; c < cEnd; ++c) {
2563       PetscInt corners;
2564 
2565       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2566       if (!cornersSeen[corners]) {
2567         PetscInt nFV;
2568 
2569         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2570         cornersSeen[corners] = 1;
2571 
2572         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2573 
2574         numFaceVertices[numFaceCases++] = nFV;
2575       }
2576     }
2577   }
2578   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2579   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2580   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2581   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2582   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2583   /* Count neighboring cells */
2584   for (cell = cStart; cell < cEnd; ++cell) {
2585     PetscInt numNeighbors = maxNeighbors, n;
2586 
2587     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2588     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2589     for (n = 0; n < numNeighbors; ++n) {
2590       PetscInt        cellPair[2];
2591       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2592       PetscInt        meetSize = 0;
2593       const PetscInt *meet    = NULL;
2594 
2595       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2596       if (cellPair[0] == cellPair[1]) continue;
2597       if (!found) {
2598         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2599         if (meetSize) {
2600           PetscInt f;
2601 
2602           for (f = 0; f < numFaceCases; ++f) {
2603             if (numFaceVertices[f] == meetSize) {
2604               found = PETSC_TRUE;
2605               break;
2606             }
2607           }
2608         }
2609         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2610       }
2611       if (found) ++off[cell-cStart+1];
2612     }
2613   }
2614   /* Prefix sum */
2615   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2616 
2617   if (adjacency) {
2618     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2619     /* Get neighboring cells */
2620     for (cell = cStart; cell < cEnd; ++cell) {
2621       PetscInt numNeighbors = maxNeighbors, n;
2622       PetscInt cellOffset   = 0;
2623 
2624       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2625       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2626       for (n = 0; n < numNeighbors; ++n) {
2627         PetscInt        cellPair[2];
2628         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2629         PetscInt        meetSize = 0;
2630         const PetscInt *meet    = NULL;
2631 
2632         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2633         if (cellPair[0] == cellPair[1]) continue;
2634         if (!found) {
2635           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2636           if (meetSize) {
2637             PetscInt f;
2638 
2639             for (f = 0; f < numFaceCases; ++f) {
2640               if (numFaceVertices[f] == meetSize) {
2641                 found = PETSC_TRUE;
2642                 break;
2643               }
2644             }
2645           }
2646           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2647         }
2648         if (found) {
2649           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2650           ++cellOffset;
2651         }
2652       }
2653     }
2654   }
2655   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2656   if (numVertices) *numVertices = numCells;
2657   if (offsets)   *offsets   = off;
2658   if (adjacency) *adjacency = adj;
2659   PetscFunctionReturn(0);
2660 }
2661 
2662 #if defined(PETSC_HAVE_CHACO)
2663 #if defined(PETSC_HAVE_UNISTD_H)
2664 #include <unistd.h>
2665 #endif
2666 /* Chaco does not have an include file */
2667 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2668                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2669                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2670                        int mesh_dims[3], double *goal, int global_method, int local_method,
2671                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2672 
2673 extern int FREE_GRAPH;
2674 
2675 #undef __FUNCT__
2676 #define __FUNCT__ "DMPlexPartition_Chaco"
2677 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2678 {
2679   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2680   MPI_Comm       comm;
2681   int            nvtxs          = numVertices; /* number of vertices in full graph */
2682   int           *vwgts          = NULL;   /* weights for all vertices */
2683   float         *ewgts          = NULL;   /* weights for all edges */
2684   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2685   char          *outassignname  = NULL;   /*  name of assignment output file */
2686   char          *outfilename    = NULL;   /* output file name */
2687   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2688   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2689   int            mesh_dims[3];            /* dimensions of mesh of processors */
2690   double        *goal          = NULL;    /* desired set sizes for each set */
2691   int            global_method = 1;       /* global partitioning algorithm */
2692   int            local_method  = 1;       /* local partitioning algorithm */
2693   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2694   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2695   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2696   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2697   long           seed          = 123636512; /* for random graph mutations */
2698   short int     *assignment;              /* Output partition */
2699   int            fd_stdout, fd_pipe[2];
2700   PetscInt      *points;
2701   PetscMPIInt    commSize;
2702   int            i, v, p;
2703   PetscErrorCode ierr;
2704 
2705   PetscFunctionBegin;
2706   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2707   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2708   if (!numVertices) {
2709     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2710     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2711     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2712     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2713     PetscFunctionReturn(0);
2714   }
2715   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2716   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2717 
2718   if (global_method == INERTIAL_METHOD) {
2719     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2720     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2721   }
2722   mesh_dims[0] = commSize;
2723   mesh_dims[1] = 1;
2724   mesh_dims[2] = 1;
2725   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2726   /* Chaco outputs to stdout. We redirect this to a buffer. */
2727   /* TODO: check error codes for UNIX calls */
2728 #if defined(PETSC_HAVE_UNISTD_H)
2729   {
2730     int piperet;
2731     piperet = pipe(fd_pipe);
2732     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2733     fd_stdout = dup(1);
2734     close(1);
2735     dup2(fd_pipe[1], 1);
2736   }
2737 #endif
2738   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2739                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2740                    vmax, ndims, eigtol, seed);
2741 #if defined(PETSC_HAVE_UNISTD_H)
2742   {
2743     char msgLog[10000];
2744     int  count;
2745 
2746     fflush(stdout);
2747     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2748     if (count < 0) count = 0;
2749     msgLog[count] = 0;
2750     close(1);
2751     dup2(fd_stdout, 1);
2752     close(fd_stdout);
2753     close(fd_pipe[0]);
2754     close(fd_pipe[1]);
2755     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2756   }
2757 #endif
2758   /* Convert to PetscSection+IS */
2759   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2760   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2761   for (v = 0; v < nvtxs; ++v) {
2762     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2763   }
2764   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2765   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2766   for (p = 0, i = 0; p < commSize; ++p) {
2767     for (v = 0; v < nvtxs; ++v) {
2768       if (assignment[v] == p) points[i++] = v;
2769     }
2770   }
2771   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2772   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2773   if (global_method == INERTIAL_METHOD) {
2774     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2775   }
2776   ierr = PetscFree(assignment);CHKERRQ(ierr);
2777   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2778   PetscFunctionReturn(0);
2779 }
2780 #endif
2781 
2782 #if defined(PETSC_HAVE_PARMETIS)
2783 #undef __FUNCT__
2784 #define __FUNCT__ "DMPlexPartition_ParMetis"
2785 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2786 {
2787   PetscFunctionBegin;
2788   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2789   PetscFunctionReturn(0);
2790 }
2791 #endif
2792 
2793 #undef __FUNCT__
2794 #define __FUNCT__ "DMPlexEnlargePartition"
2795 /* Expand the partition by BFS on the adjacency graph */
2796 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2797 {
2798   PetscHashI      h;
2799   const PetscInt *points;
2800   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2801   PetscInt        pStart, pEnd, part, q;
2802   PetscErrorCode  ierr;
2803 
2804   PetscFunctionBegin;
2805   PetscHashICreate(h);
2806   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2807   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2808   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2809   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2810   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2811   for (part = pStart; part < pEnd; ++part) {
2812     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2813 
2814     PetscHashIClear(h);
2815     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2816     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2817     /* Add all existing points to h */
2818     for (p = 0; p < numPoints; ++p) {
2819       const PetscInt point = points[off+p];
2820       PetscHashIAdd(h, point, 1);
2821     }
2822     PetscHashISize(h, nP);
2823     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2824     /* Add all points in next BFS level */
2825     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2826     for (p = 0; p < numPoints; ++p) {
2827       const PetscInt point = points[off+p];
2828       PetscInt       s     = start[point], e = start[point+1], a;
2829 
2830       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2831     }
2832     PetscHashISize(h, numNewPoints);
2833     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2834     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2835     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2836     totPoints += numNewPoints;
2837   }
2838   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2839   PetscHashIDestroy(h);
2840   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2841   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2842   for (part = pStart, q = 0; part < pEnd; ++part) {
2843     PetscInt numPoints, p;
2844 
2845     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2846     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2847     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2848   }
2849   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2850   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2851   PetscFunctionReturn(0);
2852 }
2853 
2854 #undef __FUNCT__
2855 #define __FUNCT__ "DMPlexCreatePartition"
2856 /*
2857   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2858 
2859   Collective on DM
2860 
2861   Input Parameters:
2862   + dm - The DM
2863   . height - The height for points in the partition
2864   - enlarge - Expand each partition with neighbors
2865 
2866   Output Parameters:
2867   + partSection - The PetscSection giving the division of points by partition
2868   . partition - The list of points by partition
2869   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2870   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2871 
2872   Level: developer
2873 
2874 .seealso DMPlexDistribute()
2875 */
2876 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2877 {
2878   PetscMPIInt    size;
2879   PetscErrorCode ierr;
2880 
2881   PetscFunctionBegin;
2882   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2883 
2884   *origPartSection = NULL;
2885   *origPartition   = NULL;
2886   if (size == 1) {
2887     PetscInt *points;
2888     PetscInt  cStart, cEnd, c;
2889 
2890     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2891     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2892     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2893     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2894     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2895     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2896     for (c = cStart; c < cEnd; ++c) points[c] = c;
2897     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2898     PetscFunctionReturn(0);
2899   }
2900   if (height == 0) {
2901     PetscInt  numVertices;
2902     PetscInt *start     = NULL;
2903     PetscInt *adjacency = NULL;
2904 
2905     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2906     if (1) {
2907 #if defined(PETSC_HAVE_CHACO)
2908       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2909 #endif
2910     } else {
2911 #if defined(PETSC_HAVE_PARMETIS)
2912       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2913 #endif
2914     }
2915     if (enlarge) {
2916       *origPartSection = *partSection;
2917       *origPartition   = *partition;
2918 
2919       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2920     }
2921     ierr = PetscFree(start);CHKERRQ(ierr);
2922     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2923 # if 0
2924   } else if (height == 1) {
2925     /* Build the dual graph for faces and partition the hypergraph */
2926     PetscInt numEdges;
2927 
2928     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2929     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2930     destroyCSR(numEdges, start, adjacency);
2931 #endif
2932   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2933   PetscFunctionReturn(0);
2934 }
2935 
2936 #undef __FUNCT__
2937 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2938 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2939 {
2940   /* const PetscInt  height = 0; */
2941   const PetscInt *partArray;
2942   PetscInt       *allPoints, *partPoints = NULL;
2943   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2944   PetscErrorCode  ierr;
2945 
2946   PetscFunctionBegin;
2947   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2948   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2949   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2950   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2951   for (rank = rStart; rank < rEnd; ++rank) {
2952     PetscInt partSize = 0;
2953     PetscInt numPoints, offset, p;
2954 
2955     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2956     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2957     for (p = 0; p < numPoints; ++p) {
2958       PetscInt  point   = partArray[offset+p], closureSize, c;
2959       PetscInt *closure = NULL;
2960 
2961       /* TODO Include support for height > 0 case */
2962       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2963       /* Merge into existing points */
2964       if (partSize+closureSize > maxPartSize) {
2965         PetscInt *tmpPoints;
2966 
2967         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2968         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2969         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2970         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2971 
2972         partPoints = tmpPoints;
2973       }
2974       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2975       partSize += closureSize;
2976 
2977       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2978       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2979     }
2980     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2981   }
2982   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2983   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2984   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2985 
2986   for (rank = rStart; rank < rEnd; ++rank) {
2987     PetscInt partSize = 0, newOffset;
2988     PetscInt numPoints, offset, p;
2989 
2990     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2991     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2992     for (p = 0; p < numPoints; ++p) {
2993       PetscInt  point   = partArray[offset+p], closureSize, c;
2994       PetscInt *closure = NULL;
2995 
2996       /* TODO Include support for height > 0 case */
2997       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2998       /* Merge into existing points */
2999       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3000       partSize += closureSize;
3001 
3002       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3003       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3004     }
3005     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3006     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3007   }
3008   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3009   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3010   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3011   PetscFunctionReturn(0);
3012 }
3013 
3014 #undef __FUNCT__
3015 #define __FUNCT__ "DMPlexDistributeField"
3016 /*
3017   Input Parameters:
3018 . originalSection
3019 , originalVec
3020 
3021   Output Parameters:
3022 . newSection
3023 . newVec
3024 */
3025 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3026 {
3027   PetscSF        fieldSF;
3028   PetscInt      *remoteOffsets, fieldSize;
3029   PetscScalar   *originalValues, *newValues;
3030   PetscErrorCode ierr;
3031 
3032   PetscFunctionBegin;
3033   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3034 
3035   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3036   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3037   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3038 
3039   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3040   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3041   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3042   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3043   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3044   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3045   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3046   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3047   PetscFunctionReturn(0);
3048 }
3049 
3050 #undef __FUNCT__
3051 #define __FUNCT__ "DMPlexDistribute"
3052 /*@C
3053   DMPlexDistribute - Distributes the mesh and any associated sections.
3054 
3055   Not Collective
3056 
3057   Input Parameter:
3058 + dm  - The original DMPlex object
3059 . partitioner - The partitioning package, or NULL for the default
3060 - overlap - The overlap of partitions, 0 is the default
3061 
3062   Output Parameter:
3063 . parallelMesh - The distributed DMPlex object, or NULL
3064 
3065   Note: If the mesh was not distributed, the return value is NULL
3066 
3067   Level: intermediate
3068 
3069 .keywords: mesh, elements
3070 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3071 @*/
3072 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3073 {
3074   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3075   MPI_Comm               comm;
3076   const PetscInt         height = 0;
3077   PetscInt               dim, numRemoteRanks;
3078   IS                     origCellPart,        cellPart,        part;
3079   PetscSection           origCellPartSection, cellPartSection, partSection;
3080   PetscSFNode           *remoteRanks;
3081   PetscSF                partSF, pointSF, coneSF;
3082   ISLocalToGlobalMapping renumbering;
3083   PetscSection           originalConeSection, newConeSection;
3084   PetscInt              *remoteOffsets;
3085   PetscInt              *cones, *newCones, newConesSize;
3086   PetscBool              flg;
3087   PetscMPIInt            rank, numProcs, p;
3088   PetscErrorCode         ierr;
3089 
3090   PetscFunctionBegin;
3091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3092   PetscValidPointer(dmParallel,4);
3093 
3094   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3095   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3096   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3097   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3098 
3099   *dmParallel = NULL;
3100   if (numProcs == 1) PetscFunctionReturn(0);
3101 
3102   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3103   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3104   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3105   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3106   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3107   if (!rank) numRemoteRanks = numProcs;
3108   else       numRemoteRanks = 0;
3109   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3110   for (p = 0; p < numRemoteRanks; ++p) {
3111     remoteRanks[p].rank  = p;
3112     remoteRanks[p].index = 0;
3113   }
3114   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3115   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3116   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3117   if (flg) {
3118     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3119     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3120     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3121     if (origCellPart) {
3122       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3123       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3124       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3125     }
3126     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3127   }
3128   /* Close the partition over the mesh */
3129   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3130   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3131   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3132   /* Create new mesh */
3133   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3134   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3135   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3136   pmesh = (DM_Plex*) (*dmParallel)->data;
3137   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3138   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3139   if (flg) {
3140     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3141     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3142     ierr = ISView(part, NULL);CHKERRQ(ierr);
3143     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3144     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3145     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3146   }
3147   /* Distribute cone section */
3148   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3149   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3150   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3151   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3152   {
3153     PetscInt pStart, pEnd, p;
3154 
3155     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3156     for (p = pStart; p < pEnd; ++p) {
3157       PetscInt coneSize;
3158       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3159       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3160     }
3161   }
3162   /* Communicate and renumber cones */
3163   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3164   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3165   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3166   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3167   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3168   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3169   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3170   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3171   if (flg) {
3172     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3173     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3174     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3175     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3176     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3177   }
3178   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3179   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3180   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3181   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3182   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3183   /* Create supports and stratify sieve */
3184   {
3185     PetscInt pStart, pEnd;
3186 
3187     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3188     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3189   }
3190   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3191   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3192   /* Distribute Coordinates */
3193   {
3194     PetscSection originalCoordSection, newCoordSection;
3195     Vec          originalCoordinates, newCoordinates;
3196     const char  *name;
3197 
3198     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3199     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3200     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3201     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3202     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3203     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3204 
3205     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3206     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3207     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3208   }
3209   /* Distribute labels */
3210   {
3211     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3212     PetscInt numLabels = 0, l;
3213 
3214     /* Bcast number of labels */
3215     while (next) {
3216       ++numLabels; next = next->next;
3217     }
3218     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3219     next = mesh->labels;
3220     for (l = 0; l < numLabels; ++l) {
3221       DMLabel         newLabel;
3222       const PetscInt *partArray;
3223       char           *name;
3224       PetscInt       *stratumSizes = NULL, *points = NULL;
3225       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3226       PetscInt        nameSize, s, p;
3227       PetscBool       isdepth;
3228       size_t          len = 0;
3229 
3230       /* Bcast name (could filter for no points) */
3231       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3232       nameSize = len;
3233       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3234       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3235       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3236       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3237       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3238       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3239       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3240       newLabel->name = name;
3241       /* Bcast numStrata (could filter for no points in stratum) */
3242       if (!rank) newLabel->numStrata = next->numStrata;
3243       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3245                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3246                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3247       /* Bcast stratumValues (could filter for no points in stratum) */
3248       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3249       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3250       /* Find size on each process and Scatter */
3251       if (!rank) {
3252         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3253         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3254         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3255         for (s = 0; s < next->numStrata; ++s) {
3256           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3257             const PetscInt point = next->points[p];
3258             PetscInt       proc;
3259 
3260             for (proc = 0; proc < numProcs; ++proc) {
3261               PetscInt dof, off, pPart;
3262 
3263               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3264               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3265               for (pPart = off; pPart < off+dof; ++pPart) {
3266                 if (partArray[pPart] == point) {
3267                   ++stratumSizes[proc*next->numStrata+s];
3268                   break;
3269                 }
3270               }
3271             }
3272           }
3273         }
3274         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3275       }
3276       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3277       /* Calculate stratumOffsets */
3278       newLabel->stratumOffsets[0] = 0;
3279       for (s = 0; s < newLabel->numStrata; ++s) {
3280         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3281       }
3282       /* Pack points and Scatter */
3283       if (!rank) {
3284         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3285         displs[0] = 0;
3286         for (p = 0; p < numProcs; ++p) {
3287           sendcnts[p] = 0;
3288           for (s = 0; s < next->numStrata; ++s) {
3289             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3290           }
3291           offsets[p]  = displs[p];
3292           displs[p+1] = displs[p] + sendcnts[p];
3293         }
3294         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3295         for (s = 0; s < next->numStrata; ++s) {
3296           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3297             const PetscInt point = next->points[p];
3298             PetscInt       proc;
3299 
3300             for (proc = 0; proc < numProcs; ++proc) {
3301               PetscInt dof, off, pPart;
3302 
3303               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3304               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3305               for (pPart = off; pPart < off+dof; ++pPart) {
3306                 if (partArray[pPart] == point) {
3307                   points[offsets[proc]++] = point;
3308                   break;
3309                 }
3310               }
3311             }
3312           }
3313         }
3314       }
3315       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3316       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3317       ierr = PetscFree(points);CHKERRQ(ierr);
3318       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3319       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3320       /* Renumber points */
3321       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3322       /* Sort points */
3323       for (s = 0; s < newLabel->numStrata; ++s) {
3324         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3325       }
3326       /* Insert into list */
3327       if (newNext) newNext->next = newLabel;
3328       else pmesh->labels = newLabel;
3329       newNext = newLabel;
3330       if (!rank) next = next->next;
3331     }
3332   }
3333   /* Cleanup Partition */
3334   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3335   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3336   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3337   ierr = ISDestroy(&part);CHKERRQ(ierr);
3338   /* Create point SF for parallel mesh */
3339   {
3340     const PetscInt *leaves;
3341     PetscSFNode    *remotePoints, *rowners, *lowners;
3342     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3343     PetscInt        pStart, pEnd;
3344 
3345     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3346     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3347     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3348     for (p=0; p<numRoots; p++) {
3349       rowners[p].rank  = -1;
3350       rowners[p].index = -1;
3351     }
3352     if (origCellPart) {
3353       /* Make sure cells in the original partition are not assigned to other procs */
3354       const PetscInt *origCells;
3355 
3356       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3357       for (p = 0; p < numProcs; ++p) {
3358         PetscInt dof, off, d;
3359 
3360         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3361         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3362         for (d = off; d < off+dof; ++d) {
3363           rowners[origCells[d]].rank = p;
3364         }
3365       }
3366       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3367     }
3368     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3369     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3370 
3371     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3372     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3373     for (p = 0; p < numLeaves; ++p) {
3374       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3375         lowners[p].rank  = rank;
3376         lowners[p].index = leaves ? leaves[p] : p;
3377       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3378         lowners[p].rank  = -2;
3379         lowners[p].index = -2;
3380       }
3381     }
3382     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3383       rowners[p].rank  = -3;
3384       rowners[p].index = -3;
3385     }
3386     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3387     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3388     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3389     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3390     for (p = 0; p < numLeaves; ++p) {
3391       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3392       if (lowners[p].rank != rank) ++numGhostPoints;
3393     }
3394     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3395     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3396     for (p = 0, gp = 0; p < numLeaves; ++p) {
3397       if (lowners[p].rank != rank) {
3398         ghostPoints[gp]        = leaves ? leaves[p] : p;
3399         remotePoints[gp].rank  = lowners[p].rank;
3400         remotePoints[gp].index = lowners[p].index;
3401         ++gp;
3402       }
3403     }
3404     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3405     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3406     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3407   }
3408   /* Cleanup */
3409   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3410   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3411   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3412   PetscFunctionReturn(0);
3413 }
3414 
3415 #undef __FUNCT__
3416 #define __FUNCT__ "DMPlexRenumber_Private"
3417 /*
3418   Reasons to renumber:
3419 
3420   1) Permute points, e.g. bandwidth reduction (Renumber)
3421 
3422     a) Must not mix strata
3423 
3424   2) Shift numbers for point insertion (Shift)
3425 
3426     a) Want operation brken into parts so that insertion can be interleaved
3427 
3428   renumbering - An IS which provides the new numbering
3429 */
3430 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3431 {
3432   PetscFunctionBegin;
3433   PetscFunctionReturn(0);
3434 }
3435 
3436 #undef __FUNCT__
3437 #define __FUNCT__ "DMPlexShiftPoint_Private"
3438 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3439 {
3440   if (depth < 0) return p;
3441   /* Cells    */ if (p < depthEnd[depth])   return p;
3442   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3443   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3444   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3445 }
3446 
3447 #undef __FUNCT__
3448 #define __FUNCT__ "DMPlexShiftSizes_Private"
3449 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3450 {
3451   PetscInt      *depthEnd;
3452   PetscInt       depth = 0, d, pStart, pEnd, p;
3453   PetscErrorCode ierr;
3454 
3455   PetscFunctionBegin;
3456   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3457   if (depth < 0) PetscFunctionReturn(0);
3458   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3459   /* Step 1: Expand chart */
3460   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3461   for (d = 0; d <= depth; ++d) {
3462     pEnd += depthShift[d];
3463     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3464   }
3465   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3466   /* Step 2: Set cone and support sizes */
3467   for (d = 0; d <= depth; ++d) {
3468     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3469     for (p = pStart; p < pEnd; ++p) {
3470       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3471       PetscInt size;
3472 
3473       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3474       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3475       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3476       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3477     }
3478   }
3479   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3480   PetscFunctionReturn(0);
3481 }
3482 
3483 #undef __FUNCT__
3484 #define __FUNCT__ "DMPlexShiftPoints_Private"
3485 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3486 {
3487   PetscInt      *depthEnd, *newpoints;
3488   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3489   PetscErrorCode ierr;
3490 
3491   PetscFunctionBegin;
3492   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3493   if (depth < 0) PetscFunctionReturn(0);
3494   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3495   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3496   for (d = 0; d <= depth; ++d) {
3497     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3498   }
3499   /* Step 5: Set cones and supports */
3500   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3501   for (p = pStart; p < pEnd; ++p) {
3502     const PetscInt *points = NULL, *orientations = NULL;
3503     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3504 
3505     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3506     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3507     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3508     for (i = 0; i < size; ++i) {
3509       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3510     }
3511     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3512     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3513     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3514     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3515     for (i = 0; i < size; ++i) {
3516       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3517     }
3518     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3519   }
3520   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3521   PetscFunctionReturn(0);
3522 }
3523 
3524 #undef __FUNCT__
3525 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3526 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3527 {
3528   PetscSection   coordSection, newCoordSection;
3529   Vec            coordinates, newCoordinates;
3530   PetscScalar   *coords, *newCoords;
3531   PetscInt      *depthEnd, coordSize;
3532   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3533   PetscErrorCode ierr;
3534 
3535   PetscFunctionBegin;
3536   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3537   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3538   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3539   for (d = 0; d <= depth; ++d) {
3540     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3541   }
3542   /* Step 8: Convert coordinates */
3543   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3544   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3545   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3546   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3547   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3548   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3549   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3550   for (v = vStartNew; v < vEndNew; ++v) {
3551     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3552     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3553   }
3554   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3555   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3556   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3557   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3558   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3559   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3560   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3561   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3562   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3563   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3564   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3565   for (v = vStart; v < vEnd; ++v) {
3566     PetscInt dof, off, noff, d;
3567 
3568     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3569     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3570     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3571     for (d = 0; d < dof; ++d) {
3572       newCoords[noff+d] = coords[off+d];
3573     }
3574   }
3575   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3576   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3577   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3578   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3579   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3580   PetscFunctionReturn(0);
3581 }
3582 
3583 #undef __FUNCT__
3584 #define __FUNCT__ "DMPlexShiftSF_Private"
3585 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3586 {
3587   PetscInt          *depthEnd;
3588   PetscInt           depth = 0, d;
3589   PetscSF            sfPoint, sfPointNew;
3590   const PetscSFNode *remotePoints;
3591   PetscSFNode       *gremotePoints;
3592   const PetscInt    *localPoints;
3593   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3594   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3595   PetscMPIInt        numProcs;
3596   PetscErrorCode     ierr;
3597 
3598   PetscFunctionBegin;
3599   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3600   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3601   for (d = 0; d <= depth; ++d) {
3602     totShift += depthShift[d];
3603     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3604   }
3605   /* Step 9: Convert pointSF */
3606   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3607   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3608   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3609   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3610   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3611   if (numRoots >= 0) {
3612     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3613     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3614     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3615     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3616     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3617     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3618     for (l = 0; l < numLeaves; ++l) {
3619       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3620       gremotePoints[l].rank  = remotePoints[l].rank;
3621       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3622     }
3623     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3624     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3625   }
3626   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3627   PetscFunctionReturn(0);
3628 }
3629 
3630 #undef __FUNCT__
3631 #define __FUNCT__ "DMPlexShiftLabels_Private"
3632 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3633 {
3634   PetscSF            sfPoint;
3635   DMLabel            vtkLabel, ghostLabel;
3636   PetscInt          *depthEnd;
3637   const PetscSFNode *leafRemote;
3638   const PetscInt    *leafLocal;
3639   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3640   PetscMPIInt        rank;
3641   PetscErrorCode     ierr;
3642 
3643   PetscFunctionBegin;
3644   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3645   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3646   for (d = 0; d <= depth; ++d) {
3647     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3648   }
3649   /* Step 10: Convert labels */
3650   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3651   for (l = 0; l < numLabels; ++l) {
3652     DMLabel         label, newlabel;
3653     const char     *lname;
3654     PetscBool       isDepth;
3655     IS              valueIS;
3656     const PetscInt *values;
3657     PetscInt        numValues, val;
3658 
3659     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3660     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3661     if (isDepth) continue;
3662     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3663     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3664     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3665     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3666     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3667     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3668     for (val = 0; val < numValues; ++val) {
3669       IS              pointIS;
3670       const PetscInt *points;
3671       PetscInt        numPoints, p;
3672 
3673       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3674       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3675       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3676       for (p = 0; p < numPoints; ++p) {
3677         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3678 
3679         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3680       }
3681       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3682       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3683     }
3684     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3685     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3686   }
3687   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3688   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3689   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3690   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3691   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3692   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3693   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3694   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3695   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3696   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3697   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3698     for (; c < leafLocal[l] && c < cEnd; ++c) {
3699       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3700     }
3701     if (leafLocal[l] >= cEnd) break;
3702     if (leafRemote[l].rank == rank) {
3703       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3704     } else {
3705       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3706     }
3707   }
3708   for (; c < cEnd; ++c) {
3709     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710   }
3711   if (0) {
3712     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3713     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3714     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3715   }
3716   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3717   for (f = fStart; f < fEnd; ++f) {
3718     PetscInt numCells;
3719 
3720     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3721     if (numCells < 2) {
3722       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3723     } else {
3724       const PetscInt *cells = NULL;
3725       PetscInt        vA, vB;
3726 
3727       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3728       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3729       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3730       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3731     }
3732   }
3733   if (0) {
3734     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3735     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3736     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3737   }
3738   PetscFunctionReturn(0);
3739 }
3740 
3741 #undef __FUNCT__
3742 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3743 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3744 {
3745   DMLabel         label;
3746   IS              valueIS;
3747   const PetscInt *values;
3748   PetscInt       *depthShift;
3749   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3750   PetscErrorCode  ierr;
3751 
3752   PetscFunctionBegin;
3753   /* Count ghost cells */
3754   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3755   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3756   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3757   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3758 
3759   *numGhostCells = 0;
3760   for (fs = 0; fs < numFS; ++fs) {
3761     PetscInt numBdFaces;
3762 
3763     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3764 
3765     *numGhostCells += numBdFaces;
3766   }
3767   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3768   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3769   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3770   if (depth >= 0) depthShift[depth] = *numGhostCells;
3771   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3772   /* Step 3: Set cone/support sizes for new points */
3773   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3774   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3775     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3776   }
3777   for (fs = 0; fs < numFS; ++fs) {
3778     IS              faceIS;
3779     const PetscInt *faces;
3780     PetscInt        numFaces, f;
3781 
3782     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3783     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3784     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3785     for (f = 0; f < numFaces; ++f) {
3786       PetscInt size;
3787 
3788       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3789       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3790       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3791     }
3792     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3793     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3794   }
3795   /* Step 4: Setup ghosted DM */
3796   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3797   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3798   /* Step 6: Set cones and supports for new points */
3799   ghostCell = cEnd;
3800   for (fs = 0; fs < numFS; ++fs) {
3801     IS              faceIS;
3802     const PetscInt *faces;
3803     PetscInt        numFaces, f;
3804 
3805     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3806     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3807     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3808     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3809       PetscInt newFace = faces[f] + *numGhostCells;
3810 
3811       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3812       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3813     }
3814     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3815     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3816   }
3817   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3818   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3819   /* Step 7: Stratify */
3820   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3823   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3824   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3825   PetscFunctionReturn(0);
3826 }
3827 
3828 #undef __FUNCT__
3829 #define __FUNCT__ "DMPlexConstructGhostCells"
3830 /*@C
3831   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3832 
3833   Collective on dm
3834 
3835   Input Parameters:
3836 + dm - The original DM
3837 - labelName - The label specifying the boundary faces (this could be auto-generated)
3838 
3839   Output Parameters:
3840 + numGhostCells - The number of ghost cells added to the DM
3841 - dmGhosted - The new DM
3842 
3843   Level: developer
3844 
3845 .seealso: DMCreate()
3846 */
3847 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3848 {
3849   DM             gdm;
3850   PetscInt       dim;
3851   PetscErrorCode ierr;
3852 
3853   PetscFunctionBegin;
3854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3855   PetscValidPointer(numGhostCells, 3);
3856   PetscValidPointer(dmGhosted, 4);
3857   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3858   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3859   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3860   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3861   switch (dim) {
3862   case 2:
3863     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3864     break;
3865   default:
3866     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3867   }
3868   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3869   *dmGhosted = gdm;
3870   PetscFunctionReturn(0);
3871 }
3872 
3873 #undef __FUNCT__
3874 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3875 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3876 {
3877   MPI_Comm        comm;
3878   IS              valueIS, *pointIS;
3879   const PetscInt *values, **splitPoints;
3880   PetscSection    coordSection;
3881   Vec             coordinates;
3882   PetscScalar    *coords;
3883   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3884   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3885   PetscErrorCode  ierr;
3886 
3887   PetscFunctionBegin;
3888   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3889   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3890   /* Count split points and add cohesive cells */
3891   if (label) {
3892     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3893     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3894     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3895   }
3896   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3897   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3898   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3899   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3900   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3901   for (d = 0; d <= depth; ++d) {
3902     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3903     numSplitPoints[d] = 0;
3904     splitPoints[d]    = NULL;
3905     pointIS[d]        = NULL;
3906   }
3907   for (sp = 0; sp < numSP; ++sp) {
3908     const PetscInt dep = values[sp];
3909 
3910     if ((dep < 0) || (dep > depth)) continue;
3911     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3912     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3913     if (pointIS[dep]) {
3914       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3915       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3916     }
3917   }
3918   if (depth >= 0) {
3919     /* Calculate number of additional points */
3920     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3921     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3922     /* Calculate hybrid bound for each dimension */
3923     pMaxNew[0] += depthShift[depth];
3924     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3925     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3926 
3927     /* Calculate point offset for each dimension */
3928     depthOffset[depth] = 0;
3929     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3930     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3931     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3932   }
3933   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3934   /* Step 3: Set cone/support sizes for new points */
3935   for (dep = 0; dep <= depth; ++dep) {
3936     for (p = 0; p < numSplitPoints[dep]; ++p) {
3937       const PetscInt  oldp   = splitPoints[dep][p];
3938       const PetscInt  newp   = depthOffset[dep] + oldp;
3939       const PetscInt  splitp = pMaxNew[dep] + p;
3940       const PetscInt *support;
3941       PetscInt        coneSize, supportSize, q, e;
3942 
3943       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3944       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3945       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3946       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3947       if (dep == depth-1) {
3948         const PetscInt ccell = pMaxNew[depth] + p;
3949         /* Add cohesive cells, they are prisms */
3950         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3951       } else if (dep == 0) {
3952         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3953 
3954         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3955         /* Split old vertex: Edges in old split faces and new cohesive edge */
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 == 1) || (val == (shift + 1))) ++q;
3961         }
3962         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3963         /* Split new vertex: Edges in new split faces and new cohesive edge */
3964         for (e = 0, q = 0; e < supportSize; ++e) {
3965           PetscInt val;
3966 
3967           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3968           if ((val == 1) || (val == -(shift + 1))) ++q;
3969         }
3970         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3971         /* Add cohesive edges */
3972         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3973         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3974       } else if (dep == dim-2) {
3975         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3976         /* Split old edge: Faces in positive side cells and old split faces */
3977         for (e = 0, q = 0; e < supportSize; ++e) {
3978           PetscInt val;
3979 
3980           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3981           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
3982         }
3983         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
3984         /* Split new edge: Faces in negative side cells and new split faces */
3985         for (e = 0, q = 0; e < supportSize; ++e) {
3986           PetscInt val;
3987 
3988           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3989           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
3990         }
3991         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
3992       }
3993     }
3994   }
3995   /* Step 4: Setup split DM */
3996   ierr = DMSetUp(sdm);CHKERRQ(ierr);
3997   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3998   /* Step 6: Set cones and supports for new points */
3999   for (dep = 0; dep <= depth; ++dep) {
4000     for (p = 0; p < numSplitPoints[dep]; ++p) {
4001       const PetscInt  oldp   = splitPoints[dep][p];
4002       const PetscInt  newp   = depthOffset[dep] + oldp;
4003       const PetscInt  splitp = pMaxNew[dep] + p;
4004       const PetscInt *cone, *support, *ornt;
4005       PetscInt        coneSize, supportSize, q, v, e, s;
4006 
4007       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4008       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4009       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4010       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4011       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4012       if (dep == depth-1) {
4013         const PetscInt  ccell = pMaxNew[depth] + p;
4014         const PetscInt *supportF;
4015 
4016         /* Split face:       copy in old face to new face to start */
4017         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4018         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4019         /* Split old face:   old vertices/edges in cone so no change */
4020         /* Split new face:   new vertices/edges in cone */
4021         for (q = 0; q < coneSize; ++q) {
4022           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4023 
4024           coneNew[2+q] = pMaxNew[dim-2] + v;
4025         }
4026         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4027         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4028         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4029         coneNew[0] = newp;
4030         coneNew[1] = splitp;
4031         for (q = 0; q < coneSize; ++q) {
4032           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4033         }
4034         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4035 
4036 
4037         for (s = 0; s < supportSize; ++s) {
4038           PetscInt val;
4039 
4040           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4041           if (val < 0) {
4042             /* Split old face:   Replace negative side cell with cohesive cell */
4043             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4044           } else {
4045             /* Split new face:   Replace positive side cell with cohesive cell */
4046             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4047           }
4048         }
4049       } else if (dep == 0) {
4050         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4051 
4052         /* Split old vertex: Edges in old split faces and new cohesive edge */
4053         for (e = 0, q = 0; e < supportSize; ++e) {
4054           PetscInt val;
4055 
4056           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4057           if ((val == 1) || (val == (shift + 1))) {
4058             supportNew[q++] = depthOffset[1] + support[e];
4059           }
4060         }
4061         supportNew[q] = cedge;
4062 
4063         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4064         /* Split new vertex: Edges in new split faces and new cohesive edge */
4065         for (e = 0, q = 0; e < supportSize; ++e) {
4066           PetscInt val, edge;
4067 
4068           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4069           if (val == 1) {
4070             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4071             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4072             supportNew[q++] = pMaxNew[1] + edge;
4073           } else if (val == -(shift + 1)) {
4074             supportNew[q++] = depthOffset[1] + support[e];
4075           }
4076         }
4077         supportNew[q] = cedge;
4078         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4079         /* Cohesive edge:    Old and new split vertex, punting on support */
4080         coneNew[0] = newp;
4081         coneNew[1] = splitp;
4082         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4083       } else if (dep == dim-2) {
4084         /* Split old edge:   old vertices in cone so no change */
4085         /* Split new edge:   new vertices in cone */
4086         for (q = 0; q < coneSize; ++q) {
4087           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4088 
4089           coneNew[q] = pMaxNew[dim-3] + v;
4090         }
4091         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4092         /* Split old edge: Faces in positive side cells and old split faces */
4093         for (e = 0, q = 0; e < supportSize; ++e) {
4094           PetscInt val;
4095 
4096           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4097           if ((val == dim-1) || (val == (shift + dim-1))) {
4098             supportNew[q++] = depthOffset[dim-1] + support[e];
4099           }
4100         }
4101         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4102         /* Split new edge: Faces in negative side cells and new split faces */
4103         for (e = 0, q = 0; e < supportSize; ++e) {
4104           PetscInt val, face;
4105 
4106           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4107           if (val == dim-1) {
4108             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4109             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4110             supportNew[q++] = pMaxNew[dim-1] + face;
4111           } else if (val == -(shift + dim-1)) {
4112             supportNew[q++] = depthOffset[dim-1] + support[e];
4113           }
4114         }
4115         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4116       }
4117     }
4118   }
4119   /* Step 6b: Replace split points in negative side cones */
4120   for (sp = 0; sp < numSP; ++sp) {
4121     PetscInt        dep = values[sp];
4122     IS              pIS;
4123     PetscInt        numPoints;
4124     const PetscInt *points;
4125 
4126     if (dep >= 0) continue;
4127     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4128     if (!pIS) continue;
4129     dep  = -dep - shift;
4130     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4131     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4132     for (p = 0; p < numPoints; ++p) {
4133       const PetscInt  oldp = points[p];
4134       const PetscInt  newp = depthOffset[dep] + oldp;
4135       const PetscInt *cone;
4136       PetscInt        coneSize, c;
4137       PetscBool       replaced = PETSC_FALSE;
4138 
4139       /* Negative edge: replace split vertex */
4140       /* Negative cell: replace split face */
4141       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4142       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4143       for (c = 0; c < coneSize; ++c) {
4144         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4145         PetscInt       csplitp, cp, val;
4146 
4147         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4148         if (val == dep-1) {
4149           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4150           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4151           csplitp  = pMaxNew[dep-1] + cp;
4152           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4153           replaced = PETSC_TRUE;
4154         }
4155       }
4156       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4157     }
4158     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4159     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4160   }
4161   /* Step 7: Stratify */
4162   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4163   /* Step 8: Coordinates */
4164   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4165   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4166   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4167   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4168   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4169     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4170     const PetscInt splitp = pMaxNew[0] + v;
4171     PetscInt       dof, off, soff, d;
4172 
4173     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4174     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4175     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4176     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4177   }
4178   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4179   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4180   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4181   /* Step 10: Labels */
4182   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4183   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4184   for (dep = 0; dep <= depth; ++dep) {
4185     for (p = 0; p < numSplitPoints[dep]; ++p) {
4186       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4187       const PetscInt splitp = pMaxNew[dep] + p;
4188       PetscInt       l;
4189 
4190       for (l = 0; l < numLabels; ++l) {
4191         DMLabel     mlabel;
4192         const char *lname;
4193         PetscInt    val;
4194 
4195         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4196         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4197         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4198         if (val >= 0) {
4199           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4200           if (dep == 0) {
4201             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4202             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4203           }
4204         }
4205       }
4206     }
4207   }
4208   for (sp = 0; sp < numSP; ++sp) {
4209     const PetscInt dep = values[sp];
4210 
4211     if ((dep < 0) || (dep > depth)) continue;
4212     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4213     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4214   }
4215   if (label) {
4216     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4217     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4218   }
4219   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4220   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4221   PetscFunctionReturn(0);
4222 }
4223 
4224 #undef __FUNCT__
4225 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4226 /*@C
4227   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4228 
4229   Collective on dm
4230 
4231   Input Parameters:
4232 + dm - The original DM
4233 - labelName - The label specifying the boundary faces (this could be auto-generated)
4234 
4235   Output Parameters:
4236 - dmSplit - The new DM
4237 
4238   Level: developer
4239 
4240 .seealso: DMCreate()
4241 */
4242 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4243 {
4244   DM             sdm;
4245   PetscInt       dim;
4246   PetscErrorCode ierr;
4247 
4248   PetscFunctionBegin;
4249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4250   PetscValidPointer(dmSplit, 4);
4251   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4252   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4253   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4254   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4255   switch (dim) {
4256   case 2:
4257   case 3:
4258     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4259     break;
4260   default:
4261     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4262   }
4263   *dmSplit = sdm;
4264   PetscFunctionReturn(0);
4265 }
4266 
4267 #undef __FUNCT__
4268 #define __FUNCT__ "DMLabelCohesiveComplete"
4269 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4270 {
4271   IS              dimIS;
4272   const PetscInt *points;
4273   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4274   PetscErrorCode  ierr;
4275 
4276   PetscFunctionBegin;
4277   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4278   /* Cell orientation for face gives the side of the fault */
4279   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4280   if (!dimIS) PetscFunctionReturn(0);
4281   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4282   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4283   for (p = 0; p < numPoints; ++p) {
4284     const PetscInt *support;
4285     PetscInt        supportSize, s;
4286 
4287     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4288     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4289     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4290     for (s = 0; s < supportSize; ++s) {
4291       const PetscInt *cone, *ornt;
4292       PetscInt        coneSize, c;
4293       PetscBool       pos = PETSC_TRUE;
4294 
4295       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4296       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4297       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4298       for (c = 0; c < coneSize; ++c) {
4299         if (cone[c] == points[p]) {
4300           if (ornt[c] >= 0) {
4301             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4302           } else {
4303             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4304             pos  = PETSC_FALSE;
4305           }
4306           break;
4307         }
4308       }
4309       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]);
4310       /* Put faces touching the fault in the label */
4311       for (c = 0; c < coneSize; ++c) {
4312         const PetscInt point = cone[c];
4313 
4314         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4315         if (val == -1) {
4316           PetscInt *closure = NULL;
4317           PetscInt  closureSize, cl;
4318 
4319           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4320           for (cl = 0; cl < closureSize*2; cl += 2) {
4321             const PetscInt clp = closure[cl];
4322 
4323             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4324             if ((val >= 0) && (val < dim-1)) {
4325               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4326               break;
4327             }
4328           }
4329           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4330         }
4331       }
4332     }
4333   }
4334   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4335   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4336   /* Search for other cells/faces/edges connected to the fault by a vertex */
4337   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4338   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4339   if (!dimIS) PetscFunctionReturn(0);
4340   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4341   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4342   for (p = 0; p < numPoints; ++p) {
4343     PetscInt *star = NULL;
4344     PetscInt  starSize, s;
4345     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4346 
4347     /* First mark cells connected to the fault */
4348     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4349     while (again) {
4350       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4351       again = 0;
4352       for (s = 0; s < starSize*2; s += 2) {
4353         const PetscInt  point = star[s];
4354         const PetscInt *cone;
4355         PetscInt        coneSize, c;
4356 
4357         if ((point < cStart) || (point >= cEnd)) continue;
4358         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4359         if (val != -1) continue;
4360         again = 2;
4361         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4362         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4363         for (c = 0; c < coneSize; ++c) {
4364           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4365           if (val != -1) {
4366             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);
4367             if (val > 0) {
4368               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4369             } else {
4370               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4371             }
4372             again = 1;
4373             break;
4374           }
4375         }
4376       }
4377     }
4378     /* Classify the rest by cell membership */
4379     for (s = 0; s < starSize*2; s += 2) {
4380       const PetscInt point = star[s];
4381 
4382       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4383       if (val == -1) {
4384         PetscInt  *sstar = NULL;
4385         PetscInt   sstarSize, ss;
4386         PetscBool  marked = PETSC_FALSE;
4387 
4388         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4389         for (ss = 0; ss < sstarSize*2; ss += 2) {
4390           const PetscInt spoint = sstar[ss];
4391 
4392           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4393           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4394           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4395           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4396           if (val > 0) {
4397             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4398           } else {
4399             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4400           }
4401           marked = PETSC_TRUE;
4402           break;
4403         }
4404         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4405         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4406       }
4407     }
4408     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4409   }
4410   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4411   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4412   PetscFunctionReturn(0);
4413 }
4414 
4415 #undef __FUNCT__
4416 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4417 /*
4418   This takes as input the common mesh generator output, a list of the vertices for each cell
4419 */
4420 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4421 {
4422   PetscInt      *cone, c, p;
4423   PetscErrorCode ierr;
4424 
4425   PetscFunctionBegin;
4426   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4427   for (c = 0; c < numCells; ++c) {
4428     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4429   }
4430   ierr = DMSetUp(dm);CHKERRQ(ierr);
4431   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4432   for (c = 0; c < numCells; ++c) {
4433     for (p = 0; p < numCorners; ++p) {
4434       cone[p] = cells[c*numCorners+p]+numCells;
4435     }
4436     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4437   }
4438   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4439   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4440   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4441   PetscFunctionReturn(0);
4442 }
4443 
4444 #undef __FUNCT__
4445 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4446 /*
4447   This takes as input the coordinates for each vertex
4448 */
4449 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4450 {
4451   PetscSection   coordSection;
4452   Vec            coordinates;
4453   PetscScalar   *coords;
4454   PetscInt       coordSize, v, d;
4455   PetscErrorCode ierr;
4456 
4457   PetscFunctionBegin;
4458   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4459   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4460   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4461   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4462   for (v = numCells; v < numCells+numVertices; ++v) {
4463     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4464     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4465   }
4466   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4467   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4468   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4469   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4470   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4471   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4472   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4473   for (v = 0; v < numVertices; ++v) {
4474     for (d = 0; d < spaceDim; ++d) {
4475       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4476     }
4477   }
4478   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4479   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4480   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4481   PetscFunctionReturn(0);
4482 }
4483 
4484 #undef __FUNCT__
4485 #define __FUNCT__ "DMPlexCreateFromCellList"
4486 /*
4487   This takes as input the common mesh generator output, a list of the vertices for each cell
4488 */
4489 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], PetscInt spaceDim, const double vertexCoords[], DM *dm)
4490 {
4491   PetscErrorCode ierr;
4492 
4493   PetscFunctionBegin;
4494   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4495   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4496   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4497   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4498   if (interpolate) {
4499     DM idm;
4500 
4501     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
4502     ierr = DMDestroy(dm);CHKERRQ(ierr);
4503     *dm  = idm;
4504   }
4505   ierr = DMPlexBuildCoordinates_Private(*dm, spaceDim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4506   PetscFunctionReturn(0);
4507 }
4508 
4509 #undef __FUNCT__
4510 #define __FUNCT__ "DMPlexCreateFromDAG"
4511 /*
4512   This takes as input the raw Hasse Diagram data
4513 */
4514 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
4515 {
4516   Vec            coordinates;
4517   PetscSection   coordSection;
4518   PetscScalar    *coords;
4519   PetscInt       coordSize, firstVertex = numPoints[depth], pStart = 0, pEnd = 0, p, v, dim, d, off;
4520   PetscErrorCode ierr;
4521 
4522   PetscFunctionBegin;
4523   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4524   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
4525   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
4526   for (p = pStart; p < pEnd; ++p) {
4527     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
4528   }
4529   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
4530   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
4531     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
4532     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
4533   }
4534   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4535   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4536   /* Build coordinates */
4537   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4538   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4539   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
4540   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
4541   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
4542     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
4543   }
4544   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4545   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4546   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4547   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4548   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4549   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4550   for (v = 0; v < numPoints[0]; ++v) {
4551     PetscInt off;
4552 
4553     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
4554     for (d = 0; d < dim; ++d) {
4555       coords[off+d] = vertexCoords[v*dim+d];
4556     }
4557   }
4558   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4559   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4560   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4561   PetscFunctionReturn(0);
4562 }
4563 
4564 #if defined(PETSC_HAVE_TRIANGLE)
4565 #include <triangle.h>
4566 
4567 #undef __FUNCT__
4568 #define __FUNCT__ "InitInput_Triangle"
4569 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4570 {
4571   PetscFunctionBegin;
4572   inputCtx->numberofpoints             = 0;
4573   inputCtx->numberofpointattributes    = 0;
4574   inputCtx->pointlist                  = NULL;
4575   inputCtx->pointattributelist         = NULL;
4576   inputCtx->pointmarkerlist            = NULL;
4577   inputCtx->numberofsegments           = 0;
4578   inputCtx->segmentlist                = NULL;
4579   inputCtx->segmentmarkerlist          = NULL;
4580   inputCtx->numberoftriangleattributes = 0;
4581   inputCtx->trianglelist               = NULL;
4582   inputCtx->numberofholes              = 0;
4583   inputCtx->holelist                   = NULL;
4584   inputCtx->numberofregions            = 0;
4585   inputCtx->regionlist                 = NULL;
4586   PetscFunctionReturn(0);
4587 }
4588 
4589 #undef __FUNCT__
4590 #define __FUNCT__ "InitOutput_Triangle"
4591 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4592 {
4593   PetscFunctionBegin;
4594   outputCtx->numberofpoints        = 0;
4595   outputCtx->pointlist             = NULL;
4596   outputCtx->pointattributelist    = NULL;
4597   outputCtx->pointmarkerlist       = NULL;
4598   outputCtx->numberoftriangles     = 0;
4599   outputCtx->trianglelist          = NULL;
4600   outputCtx->triangleattributelist = NULL;
4601   outputCtx->neighborlist          = NULL;
4602   outputCtx->segmentlist           = NULL;
4603   outputCtx->segmentmarkerlist     = NULL;
4604   outputCtx->numberofedges         = 0;
4605   outputCtx->edgelist              = NULL;
4606   outputCtx->edgemarkerlist        = NULL;
4607   PetscFunctionReturn(0);
4608 }
4609 
4610 #undef __FUNCT__
4611 #define __FUNCT__ "FiniOutput_Triangle"
4612 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4613 {
4614   PetscFunctionBegin;
4615   free(outputCtx->pointmarkerlist);
4616   free(outputCtx->edgelist);
4617   free(outputCtx->edgemarkerlist);
4618   free(outputCtx->trianglelist);
4619   free(outputCtx->neighborlist);
4620   PetscFunctionReturn(0);
4621 }
4622 
4623 #undef __FUNCT__
4624 #define __FUNCT__ "DMPlexGenerate_Triangle"
4625 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4626 {
4627   MPI_Comm             comm;
4628   PetscInt             dim              = 2;
4629   const PetscBool      createConvexHull = PETSC_FALSE;
4630   const PetscBool      constrained      = PETSC_FALSE;
4631   struct triangulateio in;
4632   struct triangulateio out;
4633   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4634   PetscMPIInt          rank;
4635   PetscErrorCode       ierr;
4636 
4637   PetscFunctionBegin;
4638   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4639   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4640   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4641   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4642   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4643 
4644   in.numberofpoints = vEnd - vStart;
4645   if (in.numberofpoints > 0) {
4646     PetscSection coordSection;
4647     Vec          coordinates;
4648     PetscScalar *array;
4649 
4650     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4651     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4652     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4653     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4654     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4655     for (v = vStart; v < vEnd; ++v) {
4656       const PetscInt idx = v - vStart;
4657       PetscInt       off, d;
4658 
4659       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4660       for (d = 0; d < dim; ++d) {
4661         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4662       }
4663       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4664     }
4665     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4666   }
4667   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4668   in.numberofsegments = eEnd - eStart;
4669   if (in.numberofsegments > 0) {
4670     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4671     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4672     for (e = eStart; e < eEnd; ++e) {
4673       const PetscInt  idx = e - eStart;
4674       const PetscInt *cone;
4675 
4676       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4677 
4678       in.segmentlist[idx*2+0] = cone[0] - vStart;
4679       in.segmentlist[idx*2+1] = cone[1] - vStart;
4680 
4681       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4682     }
4683   }
4684 #if 0 /* Do not currently support holes */
4685   PetscReal *holeCoords;
4686   PetscInt   h, d;
4687 
4688   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4689   if (in.numberofholes > 0) {
4690     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4691     for (h = 0; h < in.numberofholes; ++h) {
4692       for (d = 0; d < dim; ++d) {
4693         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4694       }
4695     }
4696   }
4697 #endif
4698   if (!rank) {
4699     char args[32];
4700 
4701     /* Take away 'Q' for verbose output */
4702     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4703     if (createConvexHull) {
4704       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4705     }
4706     if (constrained) {
4707       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4708     }
4709     triangulate(args, &in, &out, NULL);
4710   }
4711   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4712   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4713   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4714   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4715   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4716 
4717   {
4718     const PetscInt numCorners  = 3;
4719     const PetscInt numCells    = out.numberoftriangles;
4720     const PetscInt numVertices = out.numberofpoints;
4721     const int     *cells      = out.trianglelist;
4722     const double  *meshCoords = out.pointlist;
4723 
4724     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4725     /* Set labels */
4726     for (v = 0; v < numVertices; ++v) {
4727       if (out.pointmarkerlist[v]) {
4728         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4729       }
4730     }
4731     if (interpolate) {
4732       for (e = 0; e < out.numberofedges; e++) {
4733         if (out.edgemarkerlist[e]) {
4734           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4735           const PetscInt *edges;
4736           PetscInt        numEdges;
4737 
4738           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4739           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4740           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4741           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4742         }
4743       }
4744     }
4745     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4746   }
4747 #if 0 /* Do not currently support holes */
4748   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4749 #endif
4750   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4751   PetscFunctionReturn(0);
4752 }
4753 
4754 #undef __FUNCT__
4755 #define __FUNCT__ "DMPlexRefine_Triangle"
4756 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4757 {
4758   MPI_Comm             comm;
4759   PetscInt             dim  = 2;
4760   struct triangulateio in;
4761   struct triangulateio out;
4762   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4763   PetscMPIInt          rank;
4764   PetscErrorCode       ierr;
4765 
4766   PetscFunctionBegin;
4767   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4768   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4769   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4770   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4771   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4772   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4773   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4774 
4775   in.numberofpoints = vEnd - vStart;
4776   if (in.numberofpoints > 0) {
4777     PetscSection coordSection;
4778     Vec          coordinates;
4779     PetscScalar *array;
4780 
4781     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4782     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4783     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4784     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4785     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4786     for (v = vStart; v < vEnd; ++v) {
4787       const PetscInt idx = v - vStart;
4788       PetscInt       off, d;
4789 
4790       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4791       for (d = 0; d < dim; ++d) {
4792         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4793       }
4794       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4795     }
4796     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4797   }
4798   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4799 
4800   in.numberofcorners   = 3;
4801   in.numberoftriangles = cEnd - cStart;
4802 
4803   in.trianglearealist  = (double*) maxVolumes;
4804   if (in.numberoftriangles > 0) {
4805     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4806     for (c = cStart; c < cEnd; ++c) {
4807       const PetscInt idx      = c - cStart;
4808       PetscInt      *closure = NULL;
4809       PetscInt       closureSize;
4810 
4811       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4812       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4813       for (v = 0; v < 3; ++v) {
4814         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4815       }
4816       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4817     }
4818   }
4819   /* TODO: Segment markers are missing on input */
4820 #if 0 /* Do not currently support holes */
4821   PetscReal *holeCoords;
4822   PetscInt   h, d;
4823 
4824   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4825   if (in.numberofholes > 0) {
4826     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4827     for (h = 0; h < in.numberofholes; ++h) {
4828       for (d = 0; d < dim; ++d) {
4829         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4830       }
4831     }
4832   }
4833 #endif
4834   if (!rank) {
4835     char args[32];
4836 
4837     /* Take away 'Q' for verbose output */
4838     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4839     triangulate(args, &in, &out, NULL);
4840   }
4841   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4842   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4843   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4844   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4845   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4846 
4847   {
4848     const PetscInt numCorners  = 3;
4849     const PetscInt numCells    = out.numberoftriangles;
4850     const PetscInt numVertices = out.numberofpoints;
4851     const int     *cells      = out.trianglelist;
4852     const double  *meshCoords = out.pointlist;
4853     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4854 
4855     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4856     /* Set labels */
4857     for (v = 0; v < numVertices; ++v) {
4858       if (out.pointmarkerlist[v]) {
4859         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4860       }
4861     }
4862     if (interpolate) {
4863       PetscInt e;
4864 
4865       for (e = 0; e < out.numberofedges; e++) {
4866         if (out.edgemarkerlist[e]) {
4867           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4868           const PetscInt *edges;
4869           PetscInt        numEdges;
4870 
4871           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4872           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4873           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4874           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4875         }
4876       }
4877     }
4878     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4879   }
4880 #if 0 /* Do not currently support holes */
4881   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4882 #endif
4883   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4884   PetscFunctionReturn(0);
4885 }
4886 #endif
4887 
4888 #if defined(PETSC_HAVE_TETGEN)
4889 #include <tetgen.h>
4890 #undef __FUNCT__
4891 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4892 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4893 {
4894   MPI_Comm       comm;
4895   const PetscInt dim  = 3;
4896   ::tetgenio     in;
4897   ::tetgenio     out;
4898   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4899   PetscMPIInt    rank;
4900   PetscErrorCode ierr;
4901 
4902   PetscFunctionBegin;
4903   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
4904   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4905   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4906   in.numberofpoints = vEnd - vStart;
4907   if (in.numberofpoints > 0) {
4908     PetscSection coordSection;
4909     Vec          coordinates;
4910     PetscScalar *array;
4911 
4912     in.pointlist       = new double[in.numberofpoints*dim];
4913     in.pointmarkerlist = new int[in.numberofpoints];
4914 
4915     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4916     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4917     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4918     for (v = vStart; v < vEnd; ++v) {
4919       const PetscInt idx = v - vStart;
4920       PetscInt       off, d;
4921 
4922       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4923       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
4924       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4925     }
4926     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4927   }
4928   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4929 
4930   in.numberoffacets = fEnd - fStart;
4931   if (in.numberoffacets > 0) {
4932     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4933     in.facetmarkerlist = new int[in.numberoffacets];
4934     for (f = fStart; f < fEnd; ++f) {
4935       const PetscInt idx     = f - fStart;
4936       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
4937 
4938       in.facetlist[idx].numberofpolygons = 1;
4939       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4940       in.facetlist[idx].numberofholes    = 0;
4941       in.facetlist[idx].holelist         = NULL;
4942 
4943       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4944       for (p = 0; p < numPoints*2; p += 2) {
4945         const PetscInt point = points[p];
4946         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4947       }
4948 
4949       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4950       poly->numberofvertices = numVertices;
4951       poly->vertexlist       = new int[poly->numberofvertices];
4952       for (v = 0; v < numVertices; ++v) {
4953         const PetscInt vIdx = points[v] - vStart;
4954         poly->vertexlist[v] = vIdx;
4955       }
4956       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4957       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4958     }
4959   }
4960   if (!rank) {
4961     char args[32];
4962 
4963     /* Take away 'Q' for verbose output */
4964     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4965     ::tetrahedralize(args, &in, &out);
4966   }
4967   {
4968     const PetscInt numCorners  = 4;
4969     const PetscInt numCells    = out.numberoftetrahedra;
4970     const PetscInt numVertices = out.numberofpoints;
4971     const int     *cells      = out.tetrahedronlist;
4972     const double  *meshCoords = out.pointlist;
4973 
4974     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
4975     /* Set labels */
4976     for (v = 0; v < numVertices; ++v) {
4977       if (out.pointmarkerlist[v]) {
4978         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4979       }
4980     }
4981     if (interpolate) {
4982       PetscInt e;
4983 
4984       for (e = 0; e < out.numberofedges; e++) {
4985         if (out.edgemarkerlist[e]) {
4986           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4987           const PetscInt *edges;
4988           PetscInt        numEdges;
4989 
4990           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4991           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4992           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4993           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4994         }
4995       }
4996       for (f = 0; f < out.numberoftrifaces; f++) {
4997         if (out.trifacemarkerlist[f]) {
4998           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4999           const PetscInt *faces;
5000           PetscInt        numFaces;
5001 
5002           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5003           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5004           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5005           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5006         }
5007       }
5008     }
5009     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5010   }
5011   PetscFunctionReturn(0);
5012 }
5013 
5014 #undef __FUNCT__
5015 #define __FUNCT__ "DMPlexRefine_Tetgen"
5016 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5017 {
5018   MPI_Comm       comm;
5019   const PetscInt dim  = 3;
5020   ::tetgenio     in;
5021   ::tetgenio     out;
5022   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5023   PetscMPIInt    rank;
5024   PetscErrorCode ierr;
5025 
5026   PetscFunctionBegin;
5027   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5028   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5029   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5030   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5031   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5032 
5033   in.numberofpoints = vEnd - vStart;
5034   if (in.numberofpoints > 0) {
5035     PetscSection coordSection;
5036     Vec          coordinates;
5037     PetscScalar *array;
5038 
5039     in.pointlist       = new double[in.numberofpoints*dim];
5040     in.pointmarkerlist = new int[in.numberofpoints];
5041 
5042     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5043     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5044     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5045     for (v = vStart; v < vEnd; ++v) {
5046       const PetscInt idx = v - vStart;
5047       PetscInt       off, d;
5048 
5049       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5050       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5051       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5052     }
5053     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5054   }
5055   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5056 
5057   in.numberofcorners       = 4;
5058   in.numberoftetrahedra    = cEnd - cStart;
5059   in.tetrahedronvolumelist = (double*) maxVolumes;
5060   if (in.numberoftetrahedra > 0) {
5061     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5062     for (c = cStart; c < cEnd; ++c) {
5063       const PetscInt idx      = c - cStart;
5064       PetscInt      *closure = NULL;
5065       PetscInt       closureSize;
5066 
5067       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5068       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5069       for (v = 0; v < 4; ++v) {
5070         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5071       }
5072       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5073     }
5074   }
5075   /* TODO: Put in boundary faces with markers */
5076   if (!rank) {
5077     char args[32];
5078 
5079     /* Take away 'Q' for verbose output */
5080     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5081     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5082     ::tetrahedralize(args, &in, &out);
5083   }
5084   in.tetrahedronvolumelist = NULL;
5085 
5086   {
5087     const PetscInt numCorners  = 4;
5088     const PetscInt numCells    = out.numberoftetrahedra;
5089     const PetscInt numVertices = out.numberofpoints;
5090     const int     *cells      = out.tetrahedronlist;
5091     const double  *meshCoords = out.pointlist;
5092     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5093 
5094     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5095     /* Set labels */
5096     for (v = 0; v < numVertices; ++v) {
5097       if (out.pointmarkerlist[v]) {
5098         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5099       }
5100     }
5101     if (interpolate) {
5102       PetscInt e, f;
5103 
5104       for (e = 0; e < out.numberofedges; e++) {
5105         if (out.edgemarkerlist[e]) {
5106           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5107           const PetscInt *edges;
5108           PetscInt        numEdges;
5109 
5110           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5111           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5112           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5113           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5114         }
5115       }
5116       for (f = 0; f < out.numberoftrifaces; f++) {
5117         if (out.trifacemarkerlist[f]) {
5118           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5119           const PetscInt *faces;
5120           PetscInt        numFaces;
5121 
5122           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5123           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5124           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5125           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5126         }
5127       }
5128     }
5129     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5130   }
5131   PetscFunctionReturn(0);
5132 }
5133 #endif
5134 
5135 #if defined(PETSC_HAVE_CTETGEN)
5136 #include "ctetgen.h"
5137 
5138 #undef __FUNCT__
5139 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5140 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5141 {
5142   MPI_Comm       comm;
5143   const PetscInt dim  = 3;
5144   PLC           *in, *out;
5145   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5146   PetscMPIInt    rank;
5147   PetscErrorCode ierr;
5148 
5149   PetscFunctionBegin;
5150   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5151   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5152   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5153   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5154   ierr = PLCCreate(&in);CHKERRQ(ierr);
5155   ierr = PLCCreate(&out);CHKERRQ(ierr);
5156 
5157   in->numberofpoints = vEnd - vStart;
5158   if (in->numberofpoints > 0) {
5159     PetscSection coordSection;
5160     Vec          coordinates;
5161     PetscScalar *array;
5162 
5163     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5164     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5165     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5166     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5167     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5168     for (v = vStart; v < vEnd; ++v) {
5169       const PetscInt idx = v - vStart;
5170       PetscInt       off, d, m;
5171 
5172       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5173       for (d = 0; d < dim; ++d) {
5174         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5175       }
5176       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5177 
5178       in->pointmarkerlist[idx] = (int) m;
5179     }
5180     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5181   }
5182   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5183 
5184   in->numberoffacets = fEnd - fStart;
5185   if (in->numberoffacets > 0) {
5186     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5187     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5188     for (f = fStart; f < fEnd; ++f) {
5189       const PetscInt idx     = f - fStart;
5190       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5191       polygon       *poly;
5192 
5193       in->facetlist[idx].numberofpolygons = 1;
5194 
5195       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5196 
5197       in->facetlist[idx].numberofholes    = 0;
5198       in->facetlist[idx].holelist         = NULL;
5199 
5200       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5201       for (p = 0; p < numPoints*2; p += 2) {
5202         const PetscInt point = points[p];
5203         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5204       }
5205 
5206       poly                   = in->facetlist[idx].polygonlist;
5207       poly->numberofvertices = numVertices;
5208       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5209       for (v = 0; v < numVertices; ++v) {
5210         const PetscInt vIdx = points[v] - vStart;
5211         poly->vertexlist[v] = vIdx;
5212       }
5213       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5214       in->facetmarkerlist[idx] = (int) m;
5215       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5216     }
5217   }
5218   if (!rank) {
5219     TetGenOpts t;
5220 
5221     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5222     t.in        = boundary; /* Should go away */
5223     t.plc       = 1;
5224     t.quality   = 1;
5225     t.edgesout  = 1;
5226     t.zeroindex = 1;
5227     t.quiet     = 1;
5228     t.verbose   = verbose;
5229     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5230     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5231   }
5232   {
5233     const PetscInt numCorners  = 4;
5234     const PetscInt numCells    = out->numberoftetrahedra;
5235     const PetscInt numVertices = out->numberofpoints;
5236     const int     *cells      = out->tetrahedronlist;
5237     const double  *meshCoords = out->pointlist;
5238 
5239     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
5240     /* Set labels */
5241     for (v = 0; v < numVertices; ++v) {
5242       if (out->pointmarkerlist[v]) {
5243         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5244       }
5245     }
5246     if (interpolate) {
5247       PetscInt e;
5248 
5249       for (e = 0; e < out->numberofedges; e++) {
5250         if (out->edgemarkerlist[e]) {
5251           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5252           const PetscInt *edges;
5253           PetscInt        numEdges;
5254 
5255           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5256           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5257           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5258           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5259         }
5260       }
5261       for (f = 0; f < out->numberoftrifaces; f++) {
5262         if (out->trifacemarkerlist[f]) {
5263           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5264           const PetscInt *faces;
5265           PetscInt        numFaces;
5266 
5267           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5268           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5269           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5270           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5271         }
5272       }
5273     }
5274     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5275   }
5276 
5277   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5278   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5279   PetscFunctionReturn(0);
5280 }
5281 
5282 #undef __FUNCT__
5283 #define __FUNCT__ "DMPlexRefine_CTetgen"
5284 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5285 {
5286   MPI_Comm       comm;
5287   const PetscInt dim  = 3;
5288   PLC           *in, *out;
5289   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5290   PetscMPIInt    rank;
5291   PetscErrorCode ierr;
5292 
5293   PetscFunctionBegin;
5294   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5295   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5296   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5297   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5298   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5299   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5300   ierr = PLCCreate(&in);CHKERRQ(ierr);
5301   ierr = PLCCreate(&out);CHKERRQ(ierr);
5302 
5303   in->numberofpoints = vEnd - vStart;
5304   if (in->numberofpoints > 0) {
5305     PetscSection coordSection;
5306     Vec          coordinates;
5307     PetscScalar *array;
5308 
5309     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5310     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5311     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5312     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5313     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5314     for (v = vStart; v < vEnd; ++v) {
5315       const PetscInt idx = v - vStart;
5316       PetscInt       off, d, m;
5317 
5318       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5319       for (d = 0; d < dim; ++d) {
5320         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5321       }
5322       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5323 
5324       in->pointmarkerlist[idx] = (int) m;
5325     }
5326     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5327   }
5328   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5329 
5330   in->numberofcorners       = 4;
5331   in->numberoftetrahedra    = cEnd - cStart;
5332   in->tetrahedronvolumelist = maxVolumes;
5333   if (in->numberoftetrahedra > 0) {
5334     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5335     for (c = cStart; c < cEnd; ++c) {
5336       const PetscInt idx      = c - cStart;
5337       PetscInt      *closure = NULL;
5338       PetscInt       closureSize;
5339 
5340       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5341       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5342       for (v = 0; v < 4; ++v) {
5343         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5344       }
5345       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5346     }
5347   }
5348   if (!rank) {
5349     TetGenOpts t;
5350 
5351     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5352 
5353     t.in        = dm; /* Should go away */
5354     t.refine    = 1;
5355     t.varvolume = 1;
5356     t.quality   = 1;
5357     t.edgesout  = 1;
5358     t.zeroindex = 1;
5359     t.quiet     = 1;
5360     t.verbose   = verbose; /* Change this */
5361 
5362     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5363     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5364   }
5365   {
5366     const PetscInt numCorners  = 4;
5367     const PetscInt numCells    = out->numberoftetrahedra;
5368     const PetscInt numVertices = out->numberofpoints;
5369     const int     *cells       = out->tetrahedronlist;
5370     const double  *meshCoords  = out->pointlist;
5371     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5372 
5373     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
5374     /* Set labels */
5375     for (v = 0; v < numVertices; ++v) {
5376       if (out->pointmarkerlist[v]) {
5377         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5378       }
5379     }
5380     if (interpolate) {
5381       PetscInt e, f;
5382 
5383       for (e = 0; e < out->numberofedges; e++) {
5384         if (out->edgemarkerlist[e]) {
5385           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5386           const PetscInt *edges;
5387           PetscInt        numEdges;
5388 
5389           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5390           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5391           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5392           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5393         }
5394       }
5395       for (f = 0; f < out->numberoftrifaces; f++) {
5396         if (out->trifacemarkerlist[f]) {
5397           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5398           const PetscInt *faces;
5399           PetscInt        numFaces;
5400 
5401           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5402           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5403           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5404           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5405         }
5406       }
5407     }
5408     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5409   }
5410   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5411   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5412   PetscFunctionReturn(0);
5413 }
5414 #endif
5415 
5416 #undef __FUNCT__
5417 #define __FUNCT__ "DMPlexGenerate"
5418 /*@C
5419   DMPlexGenerate - Generates a mesh.
5420 
5421   Not Collective
5422 
5423   Input Parameters:
5424 + boundary - The DMPlex boundary object
5425 . name - The mesh generation package name
5426 - interpolate - Flag to create intermediate mesh elements
5427 
5428   Output Parameter:
5429 . mesh - The DMPlex object
5430 
5431   Level: intermediate
5432 
5433 .keywords: mesh, elements
5434 .seealso: DMPlexCreate(), DMRefine()
5435 @*/
5436 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5437 {
5438   PetscInt       dim;
5439   char           genname[1024];
5440   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5441   PetscErrorCode ierr;
5442 
5443   PetscFunctionBegin;
5444   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5445   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5446   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5447   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5448   if (flg) name = genname;
5449   if (name) {
5450     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5451     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5452     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5453   }
5454   switch (dim) {
5455   case 1:
5456     if (!name || isTriangle) {
5457 #if defined(PETSC_HAVE_TRIANGLE)
5458       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5459 #else
5460       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5461 #endif
5462     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5463     break;
5464   case 2:
5465     if (!name || isCTetgen) {
5466 #if defined(PETSC_HAVE_CTETGEN)
5467       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5468 #else
5469       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5470 #endif
5471     } else if (isTetgen) {
5472 #if defined(PETSC_HAVE_TETGEN)
5473       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5474 #else
5475       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5476 #endif
5477     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5478     break;
5479   default:
5480     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5481   }
5482   PetscFunctionReturn(0);
5483 }
5484 
5485 typedef PetscInt CellRefiner;
5486 
5487 #undef __FUNCT__
5488 #define __FUNCT__ "GetDepthStart_Private"
5489 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5490 {
5491   PetscFunctionBegin;
5492   if (cStart) *cStart = 0;
5493   if (vStart) *vStart = depthSize[depth];
5494   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5495   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5496   PetscFunctionReturn(0);
5497 }
5498 
5499 #undef __FUNCT__
5500 #define __FUNCT__ "GetDepthEnd_Private"
5501 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5502 {
5503   PetscFunctionBegin;
5504   if (cEnd) *cEnd = depthSize[depth];
5505   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5506   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5507   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5508   PetscFunctionReturn(0);
5509 }
5510 
5511 #undef __FUNCT__
5512 #define __FUNCT__ "CellRefinerGetSizes"
5513 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5514 {
5515   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5516   PetscErrorCode ierr;
5517 
5518   PetscFunctionBegin;
5519   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5520   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5521   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5522   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5523   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5524   switch (refiner) {
5525   case 1:
5526     /* Simplicial 2D */
5527     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5528     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5529     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5530     break;
5531   case 3:
5532     /* Hybrid 2D */
5533     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5534     cMax = PetscMin(cEnd, cMax);
5535     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5536     fMax         = PetscMin(fEnd, fMax);
5537     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5538     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 */
5539     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5540     break;
5541   case 2:
5542     /* Hex 2D */
5543     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5544     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5545     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5546     break;
5547   default:
5548     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5549   }
5550   PetscFunctionReturn(0);
5551 }
5552 
5553 #undef __FUNCT__
5554 #define __FUNCT__ "CellRefinerSetConeSizes"
5555 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5556 {
5557   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5558   PetscErrorCode ierr;
5559 
5560   PetscFunctionBegin;
5561   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5562   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5563   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5564   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5565   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5566   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5567   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5568   switch (refiner) {
5569   case 1:
5570     /* Simplicial 2D */
5571     /* All cells have 3 faces */
5572     for (c = cStart; c < cEnd; ++c) {
5573       for (r = 0; r < 4; ++r) {
5574         const PetscInt newp = (c - cStart)*4 + r;
5575 
5576         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5577       }
5578     }
5579     /* Split faces have 2 vertices and the same cells as the parent */
5580     for (f = fStart; f < fEnd; ++f) {
5581       for (r = 0; r < 2; ++r) {
5582         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5583         PetscInt       size;
5584 
5585         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5586         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5587         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5588       }
5589     }
5590     /* Interior faces have 2 vertices and 2 cells */
5591     for (c = cStart; c < cEnd; ++c) {
5592       for (r = 0; r < 3; ++r) {
5593         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5594 
5595         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5596         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5597       }
5598     }
5599     /* Old vertices have identical supports */
5600     for (v = vStart; v < vEnd; ++v) {
5601       const PetscInt newp = vStartNew + (v - vStart);
5602       PetscInt       size;
5603 
5604       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5605       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5606     }
5607     /* Face vertices have 2 + cells*2 supports */
5608     for (f = fStart; f < fEnd; ++f) {
5609       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5610       PetscInt       size;
5611 
5612       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5613       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5614     }
5615     break;
5616   case 2:
5617     /* Hex 2D */
5618     /* All cells have 4 faces */
5619     for (c = cStart; c < cEnd; ++c) {
5620       for (r = 0; r < 4; ++r) {
5621         const PetscInt newp = (c - cStart)*4 + r;
5622 
5623         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5624       }
5625     }
5626     /* Split faces have 2 vertices and the same cells as the parent */
5627     for (f = fStart; f < fEnd; ++f) {
5628       for (r = 0; r < 2; ++r) {
5629         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5630         PetscInt       size;
5631 
5632         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5633         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5634         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5635       }
5636     }
5637     /* Interior faces have 2 vertices and 2 cells */
5638     for (c = cStart; c < cEnd; ++c) {
5639       for (r = 0; r < 4; ++r) {
5640         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5641 
5642         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5643         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5644       }
5645     }
5646     /* Old vertices have identical supports */
5647     for (v = vStart; v < vEnd; ++v) {
5648       const PetscInt newp = vStartNew + (v - vStart);
5649       PetscInt       size;
5650 
5651       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5652       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5653     }
5654     /* Face vertices have 2 + cells supports */
5655     for (f = fStart; f < fEnd; ++f) {
5656       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5657       PetscInt       size;
5658 
5659       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5660       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5661     }
5662     /* Cell vertices have 4 supports */
5663     for (c = cStart; c < cEnd; ++c) {
5664       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5665 
5666       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5667     }
5668     break;
5669   case 3:
5670     /* Hybrid 2D */
5671     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5672     cMax = PetscMin(cEnd, cMax);
5673     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5674     fMax = PetscMin(fEnd, fMax);
5675     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5676     /* Interior cells have 3 faces */
5677     for (c = cStart; c < cMax; ++c) {
5678       for (r = 0; r < 4; ++r) {
5679         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5680 
5681         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5682       }
5683     }
5684     /* Hybrid cells have 4 faces */
5685     for (c = cMax; c < cEnd; ++c) {
5686       for (r = 0; r < 2; ++r) {
5687         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5688 
5689         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5690       }
5691     }
5692     /* Interior split faces have 2 vertices and the same cells as the parent */
5693     for (f = fStart; f < fMax; ++f) {
5694       for (r = 0; r < 2; ++r) {
5695         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5696         PetscInt       size;
5697 
5698         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5699         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5700         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5701       }
5702     }
5703     /* Interior cell faces have 2 vertices and 2 cells */
5704     for (c = cStart; c < cMax; ++c) {
5705       for (r = 0; r < 3; ++r) {
5706         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5707 
5708         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5709         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5710       }
5711     }
5712     /* Hybrid faces have 2 vertices and the same cells */
5713     for (f = fMax; f < fEnd; ++f) {
5714       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5715       PetscInt       size;
5716 
5717       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5718       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5719       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5720     }
5721     /* Hybrid cell faces have 2 vertices and 2 cells */
5722     for (c = cMax; c < cEnd; ++c) {
5723       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5724 
5725       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5726       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5727     }
5728     /* Old vertices have identical supports */
5729     for (v = vStart; v < vEnd; ++v) {
5730       const PetscInt newp = vStartNew + (v - vStart);
5731       PetscInt       size;
5732 
5733       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5734       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5735     }
5736     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5737     for (f = fStart; f < fMax; ++f) {
5738       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5739       const PetscInt *support;
5740       PetscInt       size, newSize = 2, s;
5741 
5742       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5743       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5744       for (s = 0; s < size; ++s) {
5745         if (support[s] >= cMax) newSize += 1;
5746         else newSize += 2;
5747       }
5748       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
5749     }
5750     break;
5751   default:
5752     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5753   }
5754   PetscFunctionReturn(0);
5755 }
5756 
5757 #undef __FUNCT__
5758 #define __FUNCT__ "CellRefinerSetCones"
5759 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5760 {
5761   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;
5762   PetscInt       maxSupportSize, *supportRef;
5763   PetscErrorCode ierr;
5764 
5765   PetscFunctionBegin;
5766   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5767   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5768   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5769   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5770   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5771   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5772   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5773   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5774   switch (refiner) {
5775   case 1:
5776     /* Simplicial 2D */
5777     /*
5778      2
5779      |\
5780      | \
5781      |  \
5782      |   \
5783      | C  \
5784      |     \
5785      |      \
5786      2---1---1
5787      |\  D  / \
5788      | 2   0   \
5789      |A \ /  B  \
5790      0---0-------1
5791      */
5792     /* All cells have 3 faces */
5793     for (c = cStart; c < cEnd; ++c) {
5794       const PetscInt  newp = cStartNew + (c - cStart)*4;
5795       const PetscInt *cone, *ornt;
5796       PetscInt        coneNew[3], orntNew[3];
5797 
5798       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5799       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5800       /* A triangle */
5801       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5802       orntNew[0] = ornt[0];
5803       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5804       orntNew[1] = -2;
5805       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5806       orntNew[2] = ornt[2];
5807       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5808       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5809 #if 1
5810       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);
5811       for (p = 0; p < 3; ++p) {
5812         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);
5813       }
5814 #endif
5815       /* B triangle */
5816       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5817       orntNew[0] = ornt[0];
5818       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5819       orntNew[1] = ornt[1];
5820       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5821       orntNew[2] = -2;
5822       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5823       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5824 #if 1
5825       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);
5826       for (p = 0; p < 3; ++p) {
5827         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);
5828       }
5829 #endif
5830       /* C triangle */
5831       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5832       orntNew[0] = -2;
5833       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5834       orntNew[1] = ornt[1];
5835       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5836       orntNew[2] = ornt[2];
5837       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5838       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5839 #if 1
5840       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);
5841       for (p = 0; p < 3; ++p) {
5842         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);
5843       }
5844 #endif
5845       /* D triangle */
5846       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5847       orntNew[0] = 0;
5848       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5849       orntNew[1] = 0;
5850       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5851       orntNew[2] = 0;
5852       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5853       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5854 #if 1
5855       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);
5856       for (p = 0; p < 3; ++p) {
5857         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);
5858       }
5859 #endif
5860     }
5861     /* Split faces have 2 vertices and the same cells as the parent */
5862     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5863     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5864     for (f = fStart; f < fEnd; ++f) {
5865       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5866 
5867       for (r = 0; r < 2; ++r) {
5868         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5869         const PetscInt *cone, *support;
5870         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5871 
5872         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5873         coneNew[0]       = vStartNew + (cone[0] - vStart);
5874         coneNew[1]       = vStartNew + (cone[1] - vStart);
5875         coneNew[(r+1)%2] = newv;
5876         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5877 #if 1
5878         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5879         for (p = 0; p < 2; ++p) {
5880           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);
5881         }
5882 #endif
5883         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5884         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5885         for (s = 0; s < supportSize; ++s) {
5886           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5887           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5888           for (c = 0; c < coneSize; ++c) {
5889             if (cone[c] == f) break;
5890           }
5891           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5892         }
5893         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5894 #if 1
5895         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5896         for (p = 0; p < supportSize; ++p) {
5897           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);
5898         }
5899 #endif
5900       }
5901     }
5902     /* Interior faces have 2 vertices and 2 cells */
5903     for (c = cStart; c < cEnd; ++c) {
5904       const PetscInt *cone;
5905 
5906       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5907       for (r = 0; r < 3; ++r) {
5908         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5909         PetscInt       coneNew[2];
5910         PetscInt       supportNew[2];
5911 
5912         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5913         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5914         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5915 #if 1
5916         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5917         for (p = 0; p < 2; ++p) {
5918           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);
5919         }
5920 #endif
5921         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5922         supportNew[1] = (c - cStart)*4 + 3;
5923         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5924 #if 1
5925         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5926         for (p = 0; p < 2; ++p) {
5927           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);
5928         }
5929 #endif
5930       }
5931     }
5932     /* Old vertices have identical supports */
5933     for (v = vStart; v < vEnd; ++v) {
5934       const PetscInt  newp = vStartNew + (v - vStart);
5935       const PetscInt *support, *cone;
5936       PetscInt        size, s;
5937 
5938       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5939       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5940       for (s = 0; s < size; ++s) {
5941         PetscInt r = 0;
5942 
5943         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5944         if (cone[1] == v) r = 1;
5945         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5946       }
5947       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5948 #if 1
5949       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5950       for (p = 0; p < size; ++p) {
5951         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);
5952       }
5953 #endif
5954     }
5955     /* Face vertices have 2 + cells*2 supports */
5956     for (f = fStart; f < fEnd; ++f) {
5957       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5958       const PetscInt *cone, *support;
5959       PetscInt        size, s;
5960 
5961       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5962       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5963       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5964       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5965       for (s = 0; s < size; ++s) {
5966         PetscInt r = 0;
5967 
5968         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5969         if      (cone[1] == f) r = 1;
5970         else if (cone[2] == f) r = 2;
5971         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5972         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5973       }
5974       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5975 #if 1
5976       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5977       for (p = 0; p < 2+size*2; ++p) {
5978         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);
5979       }
5980 #endif
5981     }
5982     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5983     break;
5984   case 2:
5985     /* Hex 2D */
5986     /*
5987      3---------2---------2
5988      |         |         |
5989      |    D    2    C    |
5990      |         |         |
5991      3----3----0----1----1
5992      |         |         |
5993      |    A    0    B    |
5994      |         |         |
5995      0---------0---------1
5996      */
5997     /* All cells have 4 faces */
5998     for (c = cStart; c < cEnd; ++c) {
5999       const PetscInt  newp = (c - cStart)*4;
6000       const PetscInt *cone, *ornt;
6001       PetscInt        coneNew[4], orntNew[4];
6002 
6003       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6004       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6005       /* A quad */
6006       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6007       orntNew[0] = ornt[0];
6008       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6009       orntNew[1] = 0;
6010       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6011       orntNew[2] = -2;
6012       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6013       orntNew[3] = ornt[3];
6014       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6015       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6016 #if 1
6017       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);
6018       for (p = 0; p < 4; ++p) {
6019         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);
6020       }
6021 #endif
6022       /* B quad */
6023       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6024       orntNew[0] = ornt[0];
6025       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6026       orntNew[1] = ornt[1];
6027       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6028       orntNew[2] = 0;
6029       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6030       orntNew[3] = -2;
6031       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6032       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6033 #if 1
6034       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);
6035       for (p = 0; p < 4; ++p) {
6036         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);
6037       }
6038 #endif
6039       /* C quad */
6040       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6041       orntNew[0] = -2;
6042       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6043       orntNew[1] = ornt[1];
6044       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6045       orntNew[2] = ornt[2];
6046       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6047       orntNew[3] = 0;
6048       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6049       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6050 #if 1
6051       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);
6052       for (p = 0; p < 4; ++p) {
6053         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);
6054       }
6055 #endif
6056       /* D quad */
6057       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6058       orntNew[0] = 0;
6059       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6060       orntNew[1] = -2;
6061       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6062       orntNew[2] = ornt[2];
6063       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6064       orntNew[3] = ornt[3];
6065       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6066       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6067 #if 1
6068       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);
6069       for (p = 0; p < 4; ++p) {
6070         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);
6071       }
6072 #endif
6073     }
6074     /* Split faces have 2 vertices and the same cells as the parent */
6075     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6076     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6077     for (f = fStart; f < fEnd; ++f) {
6078       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6079 
6080       for (r = 0; r < 2; ++r) {
6081         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6082         const PetscInt *cone, *support;
6083         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6084 
6085         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6086         coneNew[0]       = vStartNew + (cone[0] - vStart);
6087         coneNew[1]       = vStartNew + (cone[1] - vStart);
6088         coneNew[(r+1)%2] = newv;
6089         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6090 #if 1
6091         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6092         for (p = 0; p < 2; ++p) {
6093           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);
6094         }
6095 #endif
6096         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6097         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6098         for (s = 0; s < supportSize; ++s) {
6099           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6100           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6101           for (c = 0; c < coneSize; ++c) {
6102             if (cone[c] == f) break;
6103           }
6104           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6105         }
6106         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6107 #if 1
6108         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6109         for (p = 0; p < supportSize; ++p) {
6110           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);
6111         }
6112 #endif
6113       }
6114     }
6115     /* Interior faces have 2 vertices and 2 cells */
6116     for (c = cStart; c < cEnd; ++c) {
6117       const PetscInt *cone;
6118       PetscInt        coneNew[2], supportNew[2];
6119 
6120       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6121       for (r = 0; r < 4; ++r) {
6122         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6123 
6124         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6125         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6126         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6127 #if 1
6128         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6129         for (p = 0; p < 2; ++p) {
6130           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);
6131         }
6132 #endif
6133         supportNew[0] = (c - cStart)*4 + r;
6134         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6135         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6136 #if 1
6137         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6138         for (p = 0; p < 2; ++p) {
6139           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);
6140         }
6141 #endif
6142       }
6143     }
6144     /* Old vertices have identical supports */
6145     for (v = vStart; v < vEnd; ++v) {
6146       const PetscInt  newp = vStartNew + (v - vStart);
6147       const PetscInt *support, *cone;
6148       PetscInt        size, s;
6149 
6150       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6151       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6152       for (s = 0; s < size; ++s) {
6153         PetscInt r = 0;
6154 
6155         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6156         if (cone[1] == v) r = 1;
6157         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6158       }
6159       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6160 #if 1
6161       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6162       for (p = 0; p < size; ++p) {
6163         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);
6164       }
6165 #endif
6166     }
6167     /* Face vertices have 2 + cells supports */
6168     for (f = fStart; f < fEnd; ++f) {
6169       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6170       const PetscInt *cone, *support;
6171       PetscInt        size, s;
6172 
6173       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6174       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6175       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6176       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6177       for (s = 0; s < size; ++s) {
6178         PetscInt r = 0;
6179 
6180         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6181         if      (cone[1] == f) r = 1;
6182         else if (cone[2] == f) r = 2;
6183         else if (cone[3] == f) r = 3;
6184         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6185       }
6186       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6187 #if 1
6188       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6189       for (p = 0; p < 2+size; ++p) {
6190         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);
6191       }
6192 #endif
6193     }
6194     /* Cell vertices have 4 supports */
6195     for (c = cStart; c < cEnd; ++c) {
6196       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6197       PetscInt       supportNew[4];
6198 
6199       for (r = 0; r < 4; ++r) {
6200         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6201       }
6202       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6203     }
6204     break;
6205   case 3:
6206     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6207     cMax = PetscMin(cEnd, cMax);
6208     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6209     fMax = PetscMin(fEnd, fMax);
6210     /* Interior cells have 3 faces */
6211     for (c = cStart; c < cMax; ++c) {
6212       const PetscInt  newp = cStartNew + (c - cStart)*4;
6213       const PetscInt *cone, *ornt;
6214       PetscInt        coneNew[3], orntNew[3];
6215 
6216       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6217       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6218       /* A triangle */
6219       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6220       orntNew[0] = ornt[0];
6221       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6222       orntNew[1] = -2;
6223       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6224       orntNew[2] = ornt[2];
6225       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6226       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6227 #if 1
6228       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);
6229       for (p = 0; p < 3; ++p) {
6230         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);
6231       }
6232 #endif
6233       /* B triangle */
6234       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6235       orntNew[0] = ornt[0];
6236       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6237       orntNew[1] = ornt[1];
6238       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6239       orntNew[2] = -2;
6240       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6241       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6242 #if 1
6243       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);
6244       for (p = 0; p < 3; ++p) {
6245         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);
6246       }
6247 #endif
6248       /* C triangle */
6249       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6250       orntNew[0] = -2;
6251       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6252       orntNew[1] = ornt[1];
6253       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6254       orntNew[2] = ornt[2];
6255       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6256       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6257 #if 1
6258       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);
6259       for (p = 0; p < 3; ++p) {
6260         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);
6261       }
6262 #endif
6263       /* D triangle */
6264       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6265       orntNew[0] = 0;
6266       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6267       orntNew[1] = 0;
6268       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6269       orntNew[2] = 0;
6270       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6271       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6272 #if 1
6273       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);
6274       for (p = 0; p < 3; ++p) {
6275         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);
6276       }
6277 #endif
6278     }
6279     /*
6280      2----3----3
6281      |         |
6282      |    B    |
6283      |         |
6284      0----4--- 1
6285      |         |
6286      |    A    |
6287      |         |
6288      0----2----1
6289      */
6290     /* Hybrid cells have 4 faces */
6291     for (c = cMax; c < cEnd; ++c) {
6292       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6293       const PetscInt *cone, *ornt;
6294       PetscInt        coneNew[4], orntNew[4];
6295 
6296       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6297       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6298       /* A quad */
6299       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6300       orntNew[0] = ornt[0];
6301       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6302       orntNew[1] = ornt[1];
6303       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6304       orntNew[2] = 0;
6305       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6306       orntNew[3] = 0;
6307       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6308       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6309 #if 1
6310       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);
6311       for (p = 0; p < 4; ++p) {
6312         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);
6313       }
6314 #endif
6315       /* B quad */
6316       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6317       orntNew[0] = ornt[0];
6318       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6319       orntNew[1] = ornt[1];
6320       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6321       orntNew[2] = 0;
6322       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6323       orntNew[3] = 0;
6324       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6325       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6326 #if 1
6327       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);
6328       for (p = 0; p < 4; ++p) {
6329         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);
6330       }
6331 #endif
6332     }
6333     /* Interior split faces have 2 vertices and the same cells as the parent */
6334     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6335     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6336     for (f = fStart; f < fMax; ++f) {
6337       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6338 
6339       for (r = 0; r < 2; ++r) {
6340         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6341         const PetscInt *cone, *support;
6342         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6343 
6344         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6345         coneNew[0]       = vStartNew + (cone[0] - vStart);
6346         coneNew[1]       = vStartNew + (cone[1] - vStart);
6347         coneNew[(r+1)%2] = newv;
6348         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6349 #if 1
6350         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6351         for (p = 0; p < 2; ++p) {
6352           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);
6353         }
6354 #endif
6355         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6356         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6357         for (s = 0; s < supportSize; ++s) {
6358           if (support[s] >= cMax) {
6359             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6360           } else {
6361             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6362             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6363             for (c = 0; c < coneSize; ++c) {
6364               if (cone[c] == f) break;
6365             }
6366             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6367           }
6368         }
6369         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6370 #if 1
6371         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6372         for (p = 0; p < supportSize; ++p) {
6373           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);
6374         }
6375 #endif
6376       }
6377     }
6378     /* Interior cell faces have 2 vertices and 2 cells */
6379     for (c = cStart; c < cMax; ++c) {
6380       const PetscInt *cone;
6381 
6382       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6383       for (r = 0; r < 3; ++r) {
6384         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6385         PetscInt       coneNew[2];
6386         PetscInt       supportNew[2];
6387 
6388         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6389         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6390         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6391 #if 1
6392         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6393         for (p = 0; p < 2; ++p) {
6394           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);
6395         }
6396 #endif
6397         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6398         supportNew[1] = (c - cStart)*4 + 3;
6399         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6400 #if 1
6401         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6402         for (p = 0; p < 2; ++p) {
6403           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);
6404         }
6405 #endif
6406       }
6407     }
6408     /* Interior hybrid faces have 2 vertices and the same cells */
6409     for (f = fMax; f < fEnd; ++f) {
6410       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6411       const PetscInt *cone;
6412       const PetscInt *support;
6413       PetscInt        coneNew[2];
6414       PetscInt        supportNew[2];
6415       PetscInt        size, s, r;
6416 
6417       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6418       coneNew[0] = vStartNew + (cone[0] - vStart);
6419       coneNew[1] = vStartNew + (cone[1] - vStart);
6420       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6421 #if 1
6422       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6423       for (p = 0; p < 2; ++p) {
6424         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);
6425       }
6426 #endif
6427       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6428       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6429       for (s = 0; s < size; ++s) {
6430         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6431         for (r = 0; r < 2; ++r) {
6432           if (cone[r+2] == f) break;
6433         }
6434         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6435       }
6436       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6437 #if 1
6438       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6439       for (p = 0; p < size; ++p) {
6440         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);
6441       }
6442 #endif
6443     }
6444     /* Cell hybrid faces have 2 vertices and 2 cells */
6445     for (c = cMax; c < cEnd; ++c) {
6446       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6447       const PetscInt *cone;
6448       PetscInt        coneNew[2];
6449       PetscInt        supportNew[2];
6450 
6451       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6452       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6453       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6454       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6455 #if 1
6456       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6457       for (p = 0; p < 2; ++p) {
6458         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);
6459       }
6460 #endif
6461       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6462       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6463       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6464 #if 1
6465       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6466       for (p = 0; p < 2; ++p) {
6467         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);
6468       }
6469 #endif
6470     }
6471     /* Old vertices have identical supports */
6472     for (v = vStart; v < vEnd; ++v) {
6473       const PetscInt  newp = vStartNew + (v - vStart);
6474       const PetscInt *support, *cone;
6475       PetscInt        size, s;
6476 
6477       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6478       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6479       for (s = 0; s < size; ++s) {
6480         if (support[s] >= fMax) {
6481           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6482         } else {
6483           PetscInt r = 0;
6484 
6485           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6486           if (cone[1] == v) r = 1;
6487           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6488         }
6489       }
6490       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6491 #if 1
6492       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6493       for (p = 0; p < size; ++p) {
6494         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);
6495       }
6496 #endif
6497     }
6498     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6499     for (f = fStart; f < fMax; ++f) {
6500       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6501       const PetscInt *cone, *support;
6502       PetscInt        size, newSize = 2, s;
6503 
6504       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6505       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6506       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6507       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6508       for (s = 0; s < size; ++s) {
6509         PetscInt r = 0;
6510 
6511         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6512         if (support[s] >= cMax) {
6513           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6514 
6515           newSize += 1;
6516         } else {
6517           if      (cone[1] == f) r = 1;
6518           else if (cone[2] == f) r = 2;
6519           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6520           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6521 
6522           newSize += 2;
6523         }
6524       }
6525       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6526 #if 1
6527       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6528       for (p = 0; p < newSize; ++p) {
6529         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);
6530       }
6531 #endif
6532     }
6533     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6534     break;
6535   default:
6536     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6537   }
6538   PetscFunctionReturn(0);
6539 }
6540 
6541 #undef __FUNCT__
6542 #define __FUNCT__ "CellRefinerSetCoordinates"
6543 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6544 {
6545   PetscSection   coordSection, coordSectionNew;
6546   Vec            coordinates, coordinatesNew;
6547   PetscScalar   *coords, *coordsNew;
6548   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6549   PetscErrorCode ierr;
6550 
6551   PetscFunctionBegin;
6552   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6553   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6554   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6555   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6556   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6557   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6558   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6559   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6560   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6561   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6562   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6563   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6564   if (fMax < 0) fMax = fEnd;
6565   switch (refiner) {
6566   case 1:
6567   case 2:
6568   case 3:
6569     /* Simplicial and Hex 2D */
6570     /* All vertices have the dim coordinates */
6571     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6572       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6573       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6574     }
6575     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6576     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6577     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6578     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6579     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6580     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6581     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6582     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6583     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6584     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6585     /* Old vertices have the same coordinates */
6586     for (v = vStart; v < vEnd; ++v) {
6587       const PetscInt newv = vStartNew + (v - vStart);
6588       PetscInt       off, offnew, d;
6589 
6590       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6591       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6592       for (d = 0; d < dim; ++d) {
6593         coordsNew[offnew+d] = coords[off+d];
6594       }
6595     }
6596     /* Face vertices have the average of endpoint coordinates */
6597     for (f = fStart; f < fMax; ++f) {
6598       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6599       const PetscInt *cone;
6600       PetscInt        coneSize, offA, offB, offnew, d;
6601 
6602       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6603       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6604       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6605       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6606       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6607       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6608       for (d = 0; d < dim; ++d) {
6609         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6610       }
6611     }
6612     /* Just Hex 2D */
6613     if (refiner == 2) {
6614       /* Cell vertices have the average of corner coordinates */
6615       for (c = cStart; c < cEnd; ++c) {
6616         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6617         PetscInt      *cone = NULL;
6618         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6619 
6620         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6621         for (p = 0; p < closureSize*2; p += 2) {
6622           const PetscInt point = cone[p];
6623           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6624         }
6625         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6626         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6627         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6628         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6629         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6630         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6631         for (d = 0; d < dim; ++d) {
6632           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6633         }
6634         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6635       }
6636     }
6637     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6638     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6639     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6640     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6641     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6642     break;
6643   default:
6644     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6645   }
6646   PetscFunctionReturn(0);
6647 }
6648 
6649 #undef __FUNCT__
6650 #define __FUNCT__ "DMPlexCreateProcessSF"
6651 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6652 {
6653   PetscInt           numRoots, numLeaves, l;
6654   const PetscInt    *localPoints;
6655   const PetscSFNode *remotePoints;
6656   PetscInt          *localPointsNew;
6657   PetscSFNode       *remotePointsNew;
6658   PetscInt          *ranks, *ranksNew;
6659   PetscErrorCode     ierr;
6660 
6661   PetscFunctionBegin;
6662   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6663   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6664   for (l = 0; l < numLeaves; ++l) {
6665     ranks[l] = remotePoints[l].rank;
6666   }
6667   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6668   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6669   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6670   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6671   for (l = 0; l < numLeaves; ++l) {
6672     ranksNew[l]              = ranks[l];
6673     localPointsNew[l]        = l;
6674     remotePointsNew[l].index = 0;
6675     remotePointsNew[l].rank  = ranksNew[l];
6676   }
6677   ierr = PetscFree(ranks);CHKERRQ(ierr);
6678   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6679   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6680   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6681   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6682   PetscFunctionReturn(0);
6683 }
6684 
6685 #undef __FUNCT__
6686 #define __FUNCT__ "CellRefinerCreateSF"
6687 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6688 {
6689   PetscSF            sf, sfNew, sfProcess;
6690   IS                 processRanks;
6691   MPI_Datatype       depthType;
6692   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6693   const PetscInt    *localPoints, *neighbors;
6694   const PetscSFNode *remotePoints;
6695   PetscInt          *localPointsNew;
6696   PetscSFNode       *remotePointsNew;
6697   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6698   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6699   PetscErrorCode     ierr;
6700 
6701   PetscFunctionBegin;
6702   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6703   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6704   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6705   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6706   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6707   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6708   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6709   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6710   switch (refiner) {
6711   case 3:
6712     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6713     cMax = PetscMin(cEnd, cMax);
6714     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6715     fMax = PetscMin(fEnd, fMax);
6716   }
6717   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6718   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6719   /* Caculate size of new SF */
6720   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6721   if (numRoots < 0) PetscFunctionReturn(0);
6722   for (l = 0; l < numLeaves; ++l) {
6723     const PetscInt p = localPoints[l];
6724 
6725     switch (refiner) {
6726     case 1:
6727       /* Simplicial 2D */
6728       if ((p >= vStart) && (p < vEnd)) {
6729         /* Old vertices stay the same */
6730         ++numLeavesNew;
6731       } else if ((p >= fStart) && (p < fEnd)) {
6732         /* Old faces add new faces and vertex */
6733         numLeavesNew += 1 + 2;
6734       } else if ((p >= cStart) && (p < cEnd)) {
6735         /* Old cells add new cells and interior faces */
6736         numLeavesNew += 4 + 3;
6737       }
6738       break;
6739     case 2:
6740       /* Hex 2D */
6741       if ((p >= vStart) && (p < vEnd)) {
6742         /* Old vertices stay the same */
6743         ++numLeavesNew;
6744       } else if ((p >= fStart) && (p < fEnd)) {
6745         /* Old faces add new faces and vertex */
6746         numLeavesNew += 1 + 2;
6747       } else if ((p >= cStart) && (p < cEnd)) {
6748         /* Old cells add new cells and interior faces */
6749         numLeavesNew += 4 + 4;
6750       }
6751       break;
6752     default:
6753       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6754     }
6755   }
6756   /* Communicate depthSizes for each remote rank */
6757   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6758   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6759   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6760   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);
6761   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6762   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6763   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6764   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6765   for (n = 0; n < numNeighbors; ++n) {
6766     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6767   }
6768   depthSizeOld[depth]   = cMax;
6769   depthSizeOld[0]       = vMax;
6770   depthSizeOld[depth-1] = fMax;
6771   depthSizeOld[1]       = eMax;
6772 
6773   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6774   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6775 
6776   depthSizeOld[depth]   = cEnd - cStart;
6777   depthSizeOld[0]       = vEnd - vStart;
6778   depthSizeOld[depth-1] = fEnd - fStart;
6779   depthSizeOld[1]       = eEnd - eStart;
6780 
6781   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6782   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6783   for (n = 0; n < numNeighbors; ++n) {
6784     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6785   }
6786   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6787   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6788   /* Calculate new point SF */
6789   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6790   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6791   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6792   for (l = 0, m = 0; l < numLeaves; ++l) {
6793     PetscInt    p     = localPoints[l];
6794     PetscInt    rp    = remotePoints[l].index, n;
6795     PetscMPIInt rrank = remotePoints[l].rank;
6796 
6797     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6798     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6799     switch (refiner) {
6800     case 1:
6801       /* Simplicial 2D */
6802       if ((p >= vStart) && (p < vEnd)) {
6803         /* Old vertices stay the same */
6804         localPointsNew[m]        = vStartNew     + (p  - vStart);
6805         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6806         remotePointsNew[m].rank  = rrank;
6807         ++m;
6808       } else if ((p >= fStart) && (p < fEnd)) {
6809         /* Old faces add new faces and vertex */
6810         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6811         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6812         remotePointsNew[m].rank  = rrank;
6813         ++m;
6814         for (r = 0; r < 2; ++r, ++m) {
6815           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6816           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6817           remotePointsNew[m].rank  = rrank;
6818         }
6819       } else if ((p >= cStart) && (p < cEnd)) {
6820         /* Old cells add new cells and interior faces */
6821         for (r = 0; r < 4; ++r, ++m) {
6822           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6823           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6824           remotePointsNew[m].rank  = rrank;
6825         }
6826         for (r = 0; r < 3; ++r, ++m) {
6827           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6828           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6829           remotePointsNew[m].rank  = rrank;
6830         }
6831       }
6832       break;
6833     case 2:
6834       /* Hex 2D */
6835       if ((p >= vStart) && (p < vEnd)) {
6836         /* Old vertices stay the same */
6837         localPointsNew[m]        = vStartNew     + (p  - vStart);
6838         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6839         remotePointsNew[m].rank  = rrank;
6840         ++m;
6841       } else if ((p >= fStart) && (p < fEnd)) {
6842         /* Old faces add new faces and vertex */
6843         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6844         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6845         remotePointsNew[m].rank  = rrank;
6846         ++m;
6847         for (r = 0; r < 2; ++r, ++m) {
6848           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6849           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6850           remotePointsNew[m].rank  = rrank;
6851         }
6852       } else if ((p >= cStart) && (p < cEnd)) {
6853         /* Old cells add new cells and interior faces */
6854         for (r = 0; r < 4; ++r, ++m) {
6855           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6856           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6857           remotePointsNew[m].rank  = rrank;
6858         }
6859         for (r = 0; r < 4; ++r, ++m) {
6860           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6861           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6862           remotePointsNew[m].rank  = rrank;
6863         }
6864       }
6865       break;
6866     case 3:
6867       /* Hybrid simplicial 2D */
6868       if ((p >= vStart) && (p < vEnd)) {
6869         /* Old vertices stay the same */
6870         localPointsNew[m]        = vStartNew     + (p  - vStart);
6871         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6872         remotePointsNew[m].rank  = rrank;
6873         ++m;
6874       } else if ((p >= fStart) && (p < fMax)) {
6875         /* Old interior faces add new faces and vertex */
6876         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6877         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6878         remotePointsNew[m].rank  = rrank;
6879         ++m;
6880         for (r = 0; r < 2; ++r, ++m) {
6881           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6882           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6883           remotePointsNew[m].rank  = rrank;
6884         }
6885       } else if ((p >= fMax) && (p < fEnd)) {
6886         /* Old hybrid faces stay the same */
6887         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6888         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6889         remotePointsNew[m].rank  = rrank;
6890         ++m;
6891       } else if ((p >= cStart) && (p < cMax)) {
6892         /* Old interior cells add new cells and interior faces */
6893         for (r = 0; r < 4; ++r, ++m) {
6894           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6895           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6896           remotePointsNew[m].rank  = rrank;
6897         }
6898         for (r = 0; r < 3; ++r, ++m) {
6899           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6900           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6901           remotePointsNew[m].rank  = rrank;
6902         }
6903       } else if ((p >= cStart) && (p < cMax)) {
6904         /* Old hybrid cells add new cells and hybrid face */
6905         for (r = 0; r < 2; ++r, ++m) {
6906           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6907           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6908           remotePointsNew[m].rank  = rrank;
6909         }
6910         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6911         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]);
6912         remotePointsNew[m].rank  = rrank;
6913         ++m;
6914       }
6915       break;
6916     default:
6917       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6918     }
6919   }
6920   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6921   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6922   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6923   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6924   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6925   PetscFunctionReturn(0);
6926 }
6927 
6928 #undef __FUNCT__
6929 #define __FUNCT__ "CellRefinerCreateLabels"
6930 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6931 {
6932   PetscInt       numLabels, l;
6933   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
6934   PetscErrorCode ierr;
6935 
6936   PetscFunctionBegin;
6937   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6938   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6939   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6940   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6941 
6942   cStartNew = 0;
6943   vStartNew = depthSize[2];
6944   fStartNew = depthSize[2] + depthSize[0];
6945 
6946   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6947   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6948   switch (refiner) {
6949   case 3:
6950     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6951     cMax = PetscMin(cEnd, cMax);
6952     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6953     fMax = PetscMin(fEnd, fMax);
6954   }
6955   for (l = 0; l < numLabels; ++l) {
6956     DMLabel         label, labelNew;
6957     const char     *lname;
6958     PetscBool       isDepth;
6959     IS              valueIS;
6960     const PetscInt *values;
6961     PetscInt        numValues, val;
6962 
6963     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6964     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6965     if (isDepth) continue;
6966     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6967     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6968     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6969     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6970     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6971     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6972     for (val = 0; val < numValues; ++val) {
6973       IS              pointIS;
6974       const PetscInt *points;
6975       PetscInt        numPoints, n;
6976 
6977       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6978       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6979       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6980       for (n = 0; n < numPoints; ++n) {
6981         const PetscInt p = points[n];
6982         switch (refiner) {
6983         case 1:
6984           /* Simplicial 2D */
6985           if ((p >= vStart) && (p < vEnd)) {
6986             /* Old vertices stay the same */
6987             newp = vStartNew + (p - vStart);
6988             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6989           } else if ((p >= fStart) && (p < fEnd)) {
6990             /* Old faces add new faces and vertex */
6991             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6992             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6993             for (r = 0; r < 2; ++r) {
6994               newp = fStartNew + (p - fStart)*2 + r;
6995               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6996             }
6997           } else if ((p >= cStart) && (p < cEnd)) {
6998             /* Old cells add new cells and interior faces */
6999             for (r = 0; r < 4; ++r) {
7000               newp = cStartNew + (p - cStart)*4 + r;
7001               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7002             }
7003             for (r = 0; r < 3; ++r) {
7004               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7005               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7006             }
7007           }
7008           break;
7009         case 2:
7010           /* Hex 2D */
7011           if ((p >= vStart) && (p < vEnd)) {
7012             /* Old vertices stay the same */
7013             newp = vStartNew + (p - vStart);
7014             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7015           } else if ((p >= fStart) && (p < fEnd)) {
7016             /* Old faces add new faces and vertex */
7017             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7018             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7019             for (r = 0; r < 2; ++r) {
7020               newp = fStartNew + (p - fStart)*2 + r;
7021               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7022             }
7023           } else if ((p >= cStart) && (p < cEnd)) {
7024             /* Old cells add new cells and interior faces and vertex */
7025             for (r = 0; r < 4; ++r) {
7026               newp = cStartNew + (p - cStart)*4 + r;
7027               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7028             }
7029             for (r = 0; r < 4; ++r) {
7030               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7031               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7032             }
7033             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7034             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7035           }
7036           break;
7037         case 3:
7038           /* Hybrid simplicial 2D */
7039           if ((p >= vStart) && (p < vEnd)) {
7040             /* Old vertices stay the same */
7041             newp = vStartNew + (p - vStart);
7042             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7043           } else if ((p >= fStart) && (p < fMax)) {
7044             /* Old interior faces add new faces and vertex */
7045             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7046             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7047             for (r = 0; r < 2; ++r) {
7048               newp = fStartNew + (p - fStart)*2 + r;
7049               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7050             }
7051           } else if ((p >= fMax) && (p < fEnd)) {
7052             /* Old hybrid faces stay the same */
7053             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7054             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7055           } else if ((p >= cStart) && (p < cMax)) {
7056             /* Old interior cells add new cells and interior faces */
7057             for (r = 0; r < 4; ++r) {
7058               newp = cStartNew + (p - cStart)*4 + r;
7059               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7060             }
7061             for (r = 0; r < 3; ++r) {
7062               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7063               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7064             }
7065           } else if ((p >= cMax) && (p < cEnd)) {
7066             /* Old hybrid cells add new cells and hybrid face */
7067             for (r = 0; r < 2; ++r) {
7068               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7069               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7070             }
7071             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7072             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7073           }
7074           break;
7075         default:
7076           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7077         }
7078       }
7079       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7080       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7081     }
7082     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7083     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7084     if (0) {
7085       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7086       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7087       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7088     }
7089   }
7090   PetscFunctionReturn(0);
7091 }
7092 
7093 #undef __FUNCT__
7094 #define __FUNCT__ "DMPlexRefine_Uniform"
7095 /* This will only work for interpolated meshes */
7096 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7097 {
7098   DM             rdm;
7099   PetscInt      *depthSize;
7100   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7101   PetscErrorCode ierr;
7102 
7103   PetscFunctionBegin;
7104   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7105   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7106   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7107   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7108   /* Calculate number of new points of each depth */
7109   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7110   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7111   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7112   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7113   /* Step 1: Set chart */
7114   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7115   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7116   /* Step 2: Set cone/support sizes */
7117   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7118   /* Step 3: Setup refined DM */
7119   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7120   /* Step 4: Set cones and supports */
7121   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7122   /* Step 5: Stratify */
7123   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7124   /* Step 6: Set coordinates for vertices */
7125   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7126   /* Step 7: Create pointSF */
7127   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7128   /* Step 8: Create labels */
7129   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7130   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7131 
7132   *dmRefined = rdm;
7133   PetscFunctionReturn(0);
7134 }
7135 
7136 #undef __FUNCT__
7137 #define __FUNCT__ "DMPlexSetRefinementUniform"
7138 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7139 {
7140   DM_Plex *mesh = (DM_Plex*) dm->data;
7141 
7142   PetscFunctionBegin;
7143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7144   mesh->refinementUniform = refinementUniform;
7145   PetscFunctionReturn(0);
7146 }
7147 
7148 #undef __FUNCT__
7149 #define __FUNCT__ "DMPlexGetRefinementUniform"
7150 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7151 {
7152   DM_Plex *mesh = (DM_Plex*) dm->data;
7153 
7154   PetscFunctionBegin;
7155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7156   PetscValidPointer(refinementUniform,  2);
7157   *refinementUniform = mesh->refinementUniform;
7158   PetscFunctionReturn(0);
7159 }
7160 
7161 #undef __FUNCT__
7162 #define __FUNCT__ "DMPlexSetRefinementLimit"
7163 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7164 {
7165   DM_Plex *mesh = (DM_Plex*) dm->data;
7166 
7167   PetscFunctionBegin;
7168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7169   mesh->refinementLimit = refinementLimit;
7170   PetscFunctionReturn(0);
7171 }
7172 
7173 #undef __FUNCT__
7174 #define __FUNCT__ "DMPlexGetRefinementLimit"
7175 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7176 {
7177   DM_Plex *mesh = (DM_Plex*) dm->data;
7178 
7179   PetscFunctionBegin;
7180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7181   PetscValidPointer(refinementLimit,  2);
7182   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7183   *refinementLimit = mesh->refinementLimit;
7184   PetscFunctionReturn(0);
7185 }
7186 
7187 #undef __FUNCT__
7188 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7189 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7190 {
7191   PetscInt       dim, cStart, coneSize, cMax;
7192   PetscErrorCode ierr;
7193 
7194   PetscFunctionBegin;
7195   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7196   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7197   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7198   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7199   switch (dim) {
7200   case 2:
7201     switch (coneSize) {
7202     case 3:
7203       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7204       else *cellRefiner = 1; /* Triangular */
7205       break;
7206     case 4:
7207       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7208       else *cellRefiner = 2; /* Quadrilateral */
7209       break;
7210     default:
7211       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7212     }
7213     break;
7214   default:
7215     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7216   }
7217   PetscFunctionReturn(0);
7218 }
7219 
7220 #undef __FUNCT__
7221 #define __FUNCT__ "DMRefine_Plex"
7222 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7223 {
7224   PetscReal      refinementLimit;
7225   PetscInt       dim, cStart, cEnd;
7226   char           genname[1024], *name = NULL;
7227   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7228   PetscErrorCode ierr;
7229 
7230   PetscFunctionBegin;
7231   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7232   if (isUniform) {
7233     CellRefiner cellRefiner;
7234 
7235     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7236     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7237     PetscFunctionReturn(0);
7238   }
7239   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7240   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7241   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7242   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7243   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7244   if (flg) name = genname;
7245   if (name) {
7246     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7247     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7248     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7249   }
7250   switch (dim) {
7251   case 2:
7252     if (!name || isTriangle) {
7253 #if defined(PETSC_HAVE_TRIANGLE)
7254       double  *maxVolumes;
7255       PetscInt c;
7256 
7257       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7258       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7259       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7260 #else
7261       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7262 #endif
7263     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7264     break;
7265   case 3:
7266     if (!name || isCTetgen) {
7267 #if defined(PETSC_HAVE_CTETGEN)
7268       PetscReal *maxVolumes;
7269       PetscInt   c;
7270 
7271       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7272       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7273       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7274 #else
7275       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7276 #endif
7277     } else if (isTetgen) {
7278 #if defined(PETSC_HAVE_TETGEN)
7279       double  *maxVolumes;
7280       PetscInt c;
7281 
7282       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7283       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7284       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7285 #else
7286       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7287 #endif
7288     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7289     break;
7290   default:
7291     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7292   }
7293   PetscFunctionReturn(0);
7294 }
7295 
7296 #undef __FUNCT__
7297 #define __FUNCT__ "DMPlexGetDepth"
7298 /*@
7299   DMPlexGetDepth - get the number of strata
7300 
7301   Not Collective
7302 
7303   Input Parameters:
7304 . dm           - The DMPlex object
7305 
7306   Output Parameters:
7307 . depth - number of strata
7308 
7309   Level: developer
7310 
7311   Notes:
7312   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7313 
7314 .keywords: mesh, points
7315 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7316 @*/
7317 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7318 {
7319   PetscInt       d;
7320   PetscErrorCode ierr;
7321 
7322   PetscFunctionBegin;
7323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7324   PetscValidPointer(depth, 2);
7325   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7326   *depth = d-1;
7327   PetscFunctionReturn(0);
7328 }
7329 
7330 #undef __FUNCT__
7331 #define __FUNCT__ "DMPlexGetDepthStratum"
7332 /*@
7333   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7334 
7335   Not Collective
7336 
7337   Input Parameters:
7338 + dm           - The DMPlex object
7339 - stratumValue - The requested depth
7340 
7341   Output Parameters:
7342 + start - The first point at this depth
7343 - end   - One beyond the last point at this depth
7344 
7345   Level: developer
7346 
7347 .keywords: mesh, points
7348 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7349 @*/
7350 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7351 {
7352   DM_Plex       *mesh = (DM_Plex*) dm->data;
7353   DMLabel        next  = mesh->labels;
7354   PetscBool      flg   = PETSC_FALSE;
7355   PetscInt       depth;
7356   PetscErrorCode ierr;
7357 
7358   PetscFunctionBegin;
7359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7360   if (stratumValue < 0) {
7361     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7362     PetscFunctionReturn(0);
7363   } else {
7364     PetscInt pStart, pEnd;
7365 
7366     if (start) *start = 0;
7367     if (end)   *end   = 0;
7368     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7369     if (pStart == pEnd) PetscFunctionReturn(0);
7370   }
7371   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7372   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7373   /* We should have a generic GetLabel() and a Label class */
7374   while (next) {
7375     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7376     if (flg) break;
7377     next = next->next;
7378   }
7379   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7380   depth = stratumValue;
7381   if ((depth < 0) || (depth >= next->numStrata)) {
7382     if (start) *start = 0;
7383     if (end)   *end   = 0;
7384   } else {
7385     if (start) *start = next->points[next->stratumOffsets[depth]];
7386     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7387   }
7388   PetscFunctionReturn(0);
7389 }
7390 
7391 #undef __FUNCT__
7392 #define __FUNCT__ "DMPlexGetHeightStratum"
7393 /*@
7394   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7395 
7396   Not Collective
7397 
7398   Input Parameters:
7399 + dm           - The DMPlex object
7400 - stratumValue - The requested height
7401 
7402   Output Parameters:
7403 + start - The first point at this height
7404 - end   - One beyond the last point at this height
7405 
7406   Level: developer
7407 
7408 .keywords: mesh, points
7409 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7410 @*/
7411 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7412 {
7413   DM_Plex       *mesh = (DM_Plex*) dm->data;
7414   DMLabel        next  = mesh->labels;
7415   PetscBool      flg   = PETSC_FALSE;
7416   PetscInt       depth;
7417   PetscErrorCode ierr;
7418 
7419   PetscFunctionBegin;
7420   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7421   if (stratumValue < 0) {
7422     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7423   } else {
7424     PetscInt pStart, pEnd;
7425 
7426     if (start) *start = 0;
7427     if (end)   *end   = 0;
7428     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7429     if (pStart == pEnd) PetscFunctionReturn(0);
7430   }
7431   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7432   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7433   /* We should have a generic GetLabel() and a Label class */
7434   while (next) {
7435     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7436     if (flg) break;
7437     next = next->next;
7438   }
7439   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7440   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7441   if ((depth < 0) || (depth >= next->numStrata)) {
7442     if (start) *start = 0;
7443     if (end)   *end   = 0;
7444   } else {
7445     if (start) *start = next->points[next->stratumOffsets[depth]];
7446     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7447   }
7448   PetscFunctionReturn(0);
7449 }
7450 
7451 #undef __FUNCT__
7452 #define __FUNCT__ "DMPlexCreateSectionInitial"
7453 /* Set the number of dof on each point and separate by fields */
7454 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7455 {
7456   PetscInt      *numDofTot;
7457   PetscInt       pStart = 0, pEnd = 0;
7458   PetscInt       p, d, f;
7459   PetscErrorCode ierr;
7460 
7461   PetscFunctionBegin;
7462   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7463   for (d = 0; d <= dim; ++d) {
7464     numDofTot[d] = 0;
7465     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7466   }
7467   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7468   if (numFields > 0) {
7469     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7470     if (numComp) {
7471       for (f = 0; f < numFields; ++f) {
7472         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7473       }
7474     }
7475   }
7476   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7477   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7478   for (d = 0; d <= dim; ++d) {
7479     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7480     for (p = pStart; p < pEnd; ++p) {
7481       for (f = 0; f < numFields; ++f) {
7482         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7483       }
7484       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7485     }
7486   }
7487   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7488   PetscFunctionReturn(0);
7489 }
7490 
7491 #undef __FUNCT__
7492 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7493 /* Set the number of dof on each point and separate by fields
7494    If constDof is PETSC_DETERMINE, constrain every dof on the point
7495 */
7496 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7497 {
7498   PetscInt       numFields;
7499   PetscInt       bc;
7500   PetscErrorCode ierr;
7501 
7502   PetscFunctionBegin;
7503   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7504   for (bc = 0; bc < numBC; ++bc) {
7505     PetscInt        field = 0;
7506     const PetscInt *idx;
7507     PetscInt        n, i;
7508 
7509     if (numFields) field = bcField[bc];
7510     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7511     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7512     for (i = 0; i < n; ++i) {
7513       const PetscInt p        = idx[i];
7514       PetscInt       numConst = constDof;
7515 
7516       /* Constrain every dof on the point */
7517       if (numConst < 0) {
7518         if (numFields) {
7519           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7520         } else {
7521           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7522         }
7523       }
7524       if (numFields) {
7525         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7526       }
7527       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7528     }
7529     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7530   }
7531   PetscFunctionReturn(0);
7532 }
7533 
7534 #undef __FUNCT__
7535 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7536 /* Set the constrained indices on each point and separate by fields */
7537 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7538 {
7539   PetscInt      *maxConstraints;
7540   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7541   PetscErrorCode ierr;
7542 
7543   PetscFunctionBegin;
7544   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7545   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7546   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7547   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7548   for (p = pStart; p < pEnd; ++p) {
7549     PetscInt cdof;
7550 
7551     if (numFields) {
7552       for (f = 0; f < numFields; ++f) {
7553         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7554         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7555       }
7556     } else {
7557       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7558       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7559     }
7560   }
7561   for (f = 0; f < numFields; ++f) {
7562     maxConstraints[numFields] += maxConstraints[f];
7563   }
7564   if (maxConstraints[numFields]) {
7565     PetscInt *indices;
7566 
7567     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7568     for (p = pStart; p < pEnd; ++p) {
7569       PetscInt cdof, d;
7570 
7571       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7572       if (cdof) {
7573         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7574         if (numFields) {
7575           PetscInt numConst = 0, foff = 0;
7576 
7577           for (f = 0; f < numFields; ++f) {
7578             PetscInt cfdof, fdof;
7579 
7580             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7581             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7582             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7583             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7584             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7585             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7586             numConst += cfdof;
7587             foff     += fdof;
7588           }
7589           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7590         } else {
7591           for (d = 0; d < cdof; ++d) indices[d] = d;
7592         }
7593         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7594       }
7595     }
7596     ierr = PetscFree(indices);CHKERRQ(ierr);
7597   }
7598   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7599   PetscFunctionReturn(0);
7600 }
7601 
7602 #undef __FUNCT__
7603 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7604 /* Set the constrained field indices on each point */
7605 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7606 {
7607   const PetscInt *points, *indices;
7608   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7609   PetscErrorCode  ierr;
7610 
7611   PetscFunctionBegin;
7612   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7613   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7614 
7615   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7616   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7617   if (!constraintIndices) {
7618     PetscInt *idx, i;
7619 
7620     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7621     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7622     for (i = 0; i < maxDof; ++i) idx[i] = i;
7623     for (p = 0; p < numPoints; ++p) {
7624       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7625     }
7626     ierr = PetscFree(idx);CHKERRQ(ierr);
7627   } else {
7628     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7629     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7630     for (p = 0; p < numPoints; ++p) {
7631       PetscInt fcdof;
7632 
7633       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7634       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);
7635       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7636     }
7637     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7638   }
7639   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7640   PetscFunctionReturn(0);
7641 }
7642 
7643 #undef __FUNCT__
7644 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7645 /* Set the constrained indices on each point and separate by fields */
7646 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7647 {
7648   PetscInt      *indices;
7649   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7650   PetscErrorCode ierr;
7651 
7652   PetscFunctionBegin;
7653   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7654   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7655   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7656   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7657   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7658   for (p = pStart; p < pEnd; ++p) {
7659     PetscInt cdof, d;
7660 
7661     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7662     if (cdof) {
7663       PetscInt numConst = 0, foff = 0;
7664 
7665       for (f = 0; f < numFields; ++f) {
7666         const PetscInt *fcind;
7667         PetscInt        fdof, fcdof;
7668 
7669         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7670         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7671         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7672         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7673         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
7674         foff     += fdof;
7675         numConst += fcdof;
7676       }
7677       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7678       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7679     }
7680   }
7681   ierr = PetscFree(indices);CHKERRQ(ierr);
7682   PetscFunctionReturn(0);
7683 }
7684 
7685 #undef __FUNCT__
7686 #define __FUNCT__ "DMPlexCreateSection"
7687 /*@C
7688   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7689 
7690   Not Collective
7691 
7692   Input Parameters:
7693 + dm        - The DMPlex object
7694 . dim       - The spatial dimension of the problem
7695 . numFields - The number of fields in the problem
7696 . numComp   - An array of size numFields that holds the number of components for each field
7697 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7698 . numBC     - The number of boundary conditions
7699 . bcField   - An array of size numBC giving the field number for each boundry condition
7700 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7701 
7702   Output Parameter:
7703 . section - The PetscSection object
7704 
7705   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
7706   nubmer of dof for field 0 on each edge.
7707 
7708   Level: developer
7709 
7710 .keywords: mesh, elements
7711 .seealso: DMPlexCreate(), PetscSectionCreate()
7712 @*/
7713 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
7714 {
7715   PetscErrorCode ierr;
7716 
7717   PetscFunctionBegin;
7718   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7719   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7720   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7721   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7722   {
7723     PetscBool view = PETSC_FALSE;
7724 
7725     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7726     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7727   }
7728   PetscFunctionReturn(0);
7729 }
7730 
7731 #undef __FUNCT__
7732 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7733 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
7734 {
7735   PetscSection   section;
7736   PetscErrorCode ierr;
7737 
7738   PetscFunctionBegin;
7739   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7740   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7741   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7742   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7743   PetscFunctionReturn(0);
7744 }
7745 
7746 #undef __FUNCT__
7747 #define __FUNCT__ "DMPlexGetCoordinateSection"
7748 /*@
7749   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7750 
7751   Not Collective
7752 
7753   Input Parameter:
7754 . dm - The DMPlex object
7755 
7756   Output Parameter:
7757 . section - The PetscSection object
7758 
7759   Level: intermediate
7760 
7761 .keywords: mesh, coordinates
7762 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7763 @*/
7764 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
7765 {
7766   DM             cdm;
7767   PetscErrorCode ierr;
7768 
7769   PetscFunctionBegin;
7770   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7771   PetscValidPointer(section, 2);
7772   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7773   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7774   PetscFunctionReturn(0);
7775 }
7776 
7777 #undef __FUNCT__
7778 #define __FUNCT__ "DMPlexSetCoordinateSection"
7779 /*@
7780   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7781 
7782   Not Collective
7783 
7784   Input Parameters:
7785 + dm      - The DMPlex object
7786 - section - The PetscSection object
7787 
7788   Level: intermediate
7789 
7790 .keywords: mesh, coordinates
7791 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7792 @*/
7793 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
7794 {
7795   DM             cdm;
7796   PetscErrorCode ierr;
7797 
7798   PetscFunctionBegin;
7799   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7800   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
7801   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7802   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7803   PetscFunctionReturn(0);
7804 }
7805 
7806 #undef __FUNCT__
7807 #define __FUNCT__ "DMPlexGetConeSection"
7808 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
7809 {
7810   DM_Plex *mesh = (DM_Plex*) dm->data;
7811 
7812   PetscFunctionBegin;
7813   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7814   if (section) *section = mesh->coneSection;
7815   PetscFunctionReturn(0);
7816 }
7817 
7818 #undef __FUNCT__
7819 #define __FUNCT__ "DMPlexGetCones"
7820 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
7821 {
7822   DM_Plex *mesh = (DM_Plex*) dm->data;
7823 
7824   PetscFunctionBegin;
7825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7826   if (cones) *cones = mesh->cones;
7827   PetscFunctionReturn(0);
7828 }
7829 
7830 #undef __FUNCT__
7831 #define __FUNCT__ "DMPlexGetConeOrientations"
7832 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
7833 {
7834   DM_Plex *mesh = (DM_Plex*) dm->data;
7835 
7836   PetscFunctionBegin;
7837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7838   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7839   PetscFunctionReturn(0);
7840 }
7841 
7842 #undef __FUNCT__
7843 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7844 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7845 {
7846   const PetscInt embedDim = 2;
7847   PetscReal      x        = PetscRealPart(point[0]);
7848   PetscReal      y        = PetscRealPart(point[1]);
7849   PetscReal      v0[2], J[4], invJ[4], detJ;
7850   PetscReal      xi, eta;
7851   PetscErrorCode ierr;
7852 
7853   PetscFunctionBegin;
7854   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7855   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7856   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7857 
7858   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
7859   else *cell = -1;
7860   PetscFunctionReturn(0);
7861 }
7862 
7863 #undef __FUNCT__
7864 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7865 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7866 {
7867   PetscSection       coordSection;
7868   Vec                coordsLocal;
7869   const PetscScalar *coords;
7870   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7871   PetscReal          x         = PetscRealPart(point[0]);
7872   PetscReal          y         = PetscRealPart(point[1]);
7873   PetscInt           crossings = 0, f;
7874   PetscErrorCode     ierr;
7875 
7876   PetscFunctionBegin;
7877   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7878   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7879   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7880   for (f = 0; f < 4; ++f) {
7881     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7882     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7883     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7884     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7885     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7886     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7887     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7888     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7889     if ((cond1 || cond2)  && above) ++crossings;
7890   }
7891   if (crossings % 2) *cell = c;
7892   else *cell = -1;
7893   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7894   PetscFunctionReturn(0);
7895 }
7896 
7897 #undef __FUNCT__
7898 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7899 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7900 {
7901   const PetscInt embedDim = 3;
7902   PetscReal      v0[3], J[9], invJ[9], detJ;
7903   PetscReal      x = PetscRealPart(point[0]);
7904   PetscReal      y = PetscRealPart(point[1]);
7905   PetscReal      z = PetscRealPart(point[2]);
7906   PetscReal      xi, eta, zeta;
7907   PetscErrorCode ierr;
7908 
7909   PetscFunctionBegin;
7910   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7911   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7912   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7913   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7914 
7915   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
7916   else *cell = -1;
7917   PetscFunctionReturn(0);
7918 }
7919 
7920 #undef __FUNCT__
7921 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7922 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7923 {
7924   PetscSection       coordSection;
7925   Vec                coordsLocal;
7926   const PetscScalar *coords;
7927   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7928                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7929   PetscBool          found = PETSC_TRUE;
7930   PetscInt           f;
7931   PetscErrorCode     ierr;
7932 
7933   PetscFunctionBegin;
7934   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7935   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7936   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7937   for (f = 0; f < 6; ++f) {
7938     /* Check the point is under plane */
7939     /*   Get face normal */
7940     PetscReal v_i[3];
7941     PetscReal v_j[3];
7942     PetscReal normal[3];
7943     PetscReal pp[3];
7944     PetscReal dot;
7945 
7946     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
7947     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
7948     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
7949     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
7950     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
7951     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
7952     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
7953     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
7954     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
7955     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
7956     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
7957     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
7958     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7959 
7960     /* Check that projected point is in face (2D location problem) */
7961     if (dot < 0.0) {
7962       found = PETSC_FALSE;
7963       break;
7964     }
7965   }
7966   if (found) *cell = c;
7967   else *cell = -1;
7968   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
7969   PetscFunctionReturn(0);
7970 }
7971 
7972 #undef __FUNCT__
7973 #define __FUNCT__ "DMLocatePoints_Plex"
7974 /*
7975  Need to implement using the guess
7976 */
7977 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7978 {
7979   PetscInt       cell = -1 /*, guess = -1*/;
7980   PetscInt       bs, numPoints, p;
7981   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7982   PetscInt      *cells;
7983   PetscScalar   *a;
7984   PetscErrorCode ierr;
7985 
7986   PetscFunctionBegin;
7987   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7988   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7989   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7990   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7991   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7992   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7993   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7994   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);
7995   numPoints /= bs;
7996   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7997   for (p = 0; p < numPoints; ++p) {
7998     const PetscScalar *point = &a[p*bs];
7999 
8000     switch (dim) {
8001     case 2:
8002       for (c = cStart; c < cEnd; ++c) {
8003         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8004         switch (coneSize) {
8005         case 3:
8006           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8007           break;
8008         case 4:
8009           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8010           break;
8011         default:
8012           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8013         }
8014         if (cell >= 0) break;
8015       }
8016       break;
8017     case 3:
8018       for (c = cStart; c < cEnd; ++c) {
8019         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8020         switch (coneSize) {
8021         case 4:
8022           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8023           break;
8024         case 8:
8025           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8026           break;
8027         default:
8028           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8029         }
8030         if (cell >= 0) break;
8031       }
8032       break;
8033     default:
8034       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8035     }
8036     cells[p] = cell;
8037   }
8038   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8039   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8040   PetscFunctionReturn(0);
8041 }
8042 
8043 /******************************** FEM Support **********************************/
8044 
8045 #undef __FUNCT__
8046 #define __FUNCT__ "DMPlexVecGetClosure"
8047 /*@C
8048   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8049 
8050   Not collective
8051 
8052   Input Parameters:
8053 + dm - The DM
8054 . section - The section describing the layout in v, or NULL to use the default section
8055 . v - The local vector
8056 - point - The sieve point in the DM
8057 
8058   Output Parameters:
8059 + csize - The number of values in the closure, or NULL
8060 - values - The array of values, which is a borrowed array and should not be freed
8061 
8062   Level: intermediate
8063 
8064 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8065 @*/
8066 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8067 {
8068   PetscScalar   *array, *vArray;
8069   PetscInt      *points = NULL;
8070   PetscInt       offsets[32];
8071   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8072   PetscErrorCode ierr;
8073 
8074   PetscFunctionBegin;
8075   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8076   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8077   if (!section) {
8078     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8079   }
8080   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8081   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8082   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8083   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8084   /* Compress out points not in the section */
8085   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8086   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8087     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8088       points[q*2]   = points[p];
8089       points[q*2+1] = points[p+1];
8090       ++q;
8091     }
8092   }
8093   numPoints = q;
8094   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8095     PetscInt dof, fdof;
8096 
8097     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8098     for (f = 0; f < numFields; ++f) {
8099       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8100       offsets[f+1] += fdof;
8101     }
8102     size += dof;
8103   }
8104   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8105   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8106   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8107   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8108   for (p = 0; p < numPoints*2; p += 2) {
8109     PetscInt     o = points[p+1];
8110     PetscInt     dof, off, d;
8111     PetscScalar *varr;
8112 
8113     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8114     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8115     varr = &vArray[off];
8116     if (numFields) {
8117       PetscInt fdof, foff, fcomp, f, c;
8118 
8119       for (f = 0, foff = 0; f < numFields; ++f) {
8120         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8121         if (o >= 0) {
8122           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8123             array[offsets[f]] = varr[foff+d];
8124           }
8125         } else {
8126           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8127           for (d = fdof/fcomp-1; d >= 0; --d) {
8128             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8129               array[offsets[f]] = varr[foff+d*fcomp+c];
8130             }
8131           }
8132         }
8133         foff += fdof;
8134       }
8135     } else {
8136       if (o >= 0) {
8137         for (d = 0; d < dof; ++d, ++offsets[0]) {
8138           array[offsets[0]] = varr[d];
8139         }
8140       } else {
8141         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8142           array[offsets[0]] = varr[d];
8143         }
8144       }
8145     }
8146   }
8147   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8148   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8149   if (csize) *csize = size;
8150   *values = array;
8151   PetscFunctionReturn(0);
8152 }
8153 
8154 #undef __FUNCT__
8155 #define __FUNCT__ "DMPlexVecRestoreClosure"
8156 /*@C
8157   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8158 
8159   Not collective
8160 
8161   Input Parameters:
8162 + dm - The DM
8163 . section - The section describing the layout in v, or NULL to use the default section
8164 . v - The local vector
8165 . point - The sieve point in the DM
8166 . csize - The number of values in the closure, or NULL
8167 - values - The array of values, which is a borrowed array and should not be freed
8168 
8169   Level: intermediate
8170 
8171 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8172 @*/
8173 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8174 {
8175   PetscInt       size = 0;
8176   PetscErrorCode ierr;
8177 
8178   PetscFunctionBegin;
8179   /* Should work without recalculating size */
8180   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8181   PetscFunctionReturn(0);
8182 }
8183 
8184 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8185 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8186 
8187 #undef __FUNCT__
8188 #define __FUNCT__ "updatePoint_private"
8189 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8190 {
8191   PetscInt        cdof;   /* The number of constraints on this point */
8192   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8193   PetscScalar    *a;
8194   PetscInt        off, cind = 0, k;
8195   PetscErrorCode  ierr;
8196 
8197   PetscFunctionBegin;
8198   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8199   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8200   a    = &array[off];
8201   if (!cdof || setBC) {
8202     if (orientation >= 0) {
8203       for (k = 0; k < dof; ++k) {
8204         fuse(&a[k], values[k]);
8205       }
8206     } else {
8207       for (k = 0; k < dof; ++k) {
8208         fuse(&a[k], values[dof-k-1]);
8209       }
8210     }
8211   } else {
8212     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8213     if (orientation >= 0) {
8214       for (k = 0; k < dof; ++k) {
8215         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8216         fuse(&a[k], values[k]);
8217       }
8218     } else {
8219       for (k = 0; k < dof; ++k) {
8220         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8221         fuse(&a[k], values[dof-k-1]);
8222       }
8223     }
8224   }
8225   PetscFunctionReturn(0);
8226 }
8227 
8228 #undef __FUNCT__
8229 #define __FUNCT__ "updatePointFields_private"
8230 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8231 {
8232   PetscScalar   *a;
8233   PetscInt       numFields, off, foff, f;
8234   PetscErrorCode ierr;
8235 
8236   PetscFunctionBegin;
8237   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8238   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8239   a    = &array[off];
8240   for (f = 0, foff = 0; f < numFields; ++f) {
8241     PetscInt        fdof, fcomp, fcdof;
8242     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8243     PetscInt        cind = 0, k, c;
8244 
8245     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8246     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8247     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8248     if (!fcdof || setBC) {
8249       if (orientation >= 0) {
8250         for (k = 0; k < fdof; ++k) {
8251           fuse(&a[foff+k], values[foffs[f]+k]);
8252         }
8253       } else {
8254         for (k = fdof/fcomp-1; k >= 0; --k) {
8255           for (c = 0; c < fcomp; ++c) {
8256             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8257           }
8258         }
8259       }
8260     } else {
8261       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8262       if (orientation >= 0) {
8263         for (k = 0; k < fdof; ++k) {
8264           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8265           fuse(&a[foff+k], values[foffs[f]+k]);
8266         }
8267       } else {
8268         for (k = fdof/fcomp-1; k >= 0; --k) {
8269           for (c = 0; c < fcomp; ++c) {
8270             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8271             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8272           }
8273         }
8274       }
8275     }
8276     foff     += fdof;
8277     foffs[f] += fdof;
8278   }
8279   PetscFunctionReturn(0);
8280 }
8281 
8282 #undef __FUNCT__
8283 #define __FUNCT__ "DMPlexVecSetClosure"
8284 /*@C
8285   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8286 
8287   Not collective
8288 
8289   Input Parameters:
8290 + dm - The DM
8291 . section - The section describing the layout in v, or NULL to use the default sectionw
8292 . v - The local vector
8293 . point - The sieve point in the DM
8294 . values - The array of values, which is a borrowed array and should not be freed
8295 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8296 
8297   Level: intermediate
8298 
8299 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8300 @*/
8301 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8302 {
8303   PetscScalar   *array;
8304   PetscInt      *points = NULL;
8305   PetscInt       offsets[32];
8306   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8307   PetscErrorCode ierr;
8308 
8309   PetscFunctionBegin;
8310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8311   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8312   if (!section) {
8313     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8314   }
8315   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8316   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8317   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8318   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8319   /* Compress out points not in the section */
8320   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8321   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8322     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8323       points[q*2]   = points[p];
8324       points[q*2+1] = points[p+1];
8325       ++q;
8326     }
8327   }
8328   numPoints = q;
8329   for (p = 0; p < numPoints*2; p += 2) {
8330     PetscInt fdof;
8331 
8332     for (f = 0; f < numFields; ++f) {
8333       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8334       offsets[f+1] += fdof;
8335     }
8336   }
8337   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8338   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8339   if (numFields) {
8340     switch (mode) {
8341     case INSERT_VALUES:
8342       for (p = 0; p < numPoints*2; p += 2) {
8343         PetscInt o = points[p+1];
8344         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8345       } break;
8346     case INSERT_ALL_VALUES:
8347       for (p = 0; p < numPoints*2; p += 2) {
8348         PetscInt o = points[p+1];
8349         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8350       } break;
8351     case ADD_VALUES:
8352       for (p = 0; p < numPoints*2; p += 2) {
8353         PetscInt o = points[p+1];
8354         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8355       } break;
8356     case ADD_ALL_VALUES:
8357       for (p = 0; p < numPoints*2; p += 2) {
8358         PetscInt o = points[p+1];
8359         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8360       } break;
8361     default:
8362       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8363     }
8364   } else {
8365     switch (mode) {
8366     case INSERT_VALUES:
8367       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8368         PetscInt o = points[p+1];
8369         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8370         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8371       } break;
8372     case INSERT_ALL_VALUES:
8373       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8374         PetscInt o = points[p+1];
8375         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8376         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8377       } break;
8378     case ADD_VALUES:
8379       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8380         PetscInt o = points[p+1];
8381         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8382         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8383       } break;
8384     case ADD_ALL_VALUES:
8385       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8386         PetscInt o = points[p+1];
8387         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8388         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8389       } break;
8390     default:
8391       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8392     }
8393   }
8394   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8395   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8396   PetscFunctionReturn(0);
8397 }
8398 
8399 #undef __FUNCT__
8400 #define __FUNCT__ "DMPlexPrintMatSetValues"
8401 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8402 {
8403   PetscMPIInt    rank;
8404   PetscInt       i, j;
8405   PetscErrorCode ierr;
8406 
8407   PetscFunctionBegin;
8408   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8409   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8410   for (i = 0; i < numIndices; i++) {
8411     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8412   }
8413   for (i = 0; i < numIndices; i++) {
8414     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8415     for (j = 0; j < numIndices; j++) {
8416 #if defined(PETSC_USE_COMPLEX)
8417       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8418 #else
8419       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8420 #endif
8421     }
8422     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8423   }
8424   PetscFunctionReturn(0);
8425 }
8426 
8427 #undef __FUNCT__
8428 #define __FUNCT__ "indicesPoint_private"
8429 /* . off - The global offset of this point */
8430 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8431 {
8432   PetscInt        dof;    /* The number of unknowns on this point */
8433   PetscInt        cdof;   /* The number of constraints on this point */
8434   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8435   PetscInt        cind = 0, k;
8436   PetscErrorCode  ierr;
8437 
8438   PetscFunctionBegin;
8439   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8440   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8441   if (!cdof || setBC) {
8442     if (orientation >= 0) {
8443       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8444     } else {
8445       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8446     }
8447   } else {
8448     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8449     if (orientation >= 0) {
8450       for (k = 0; k < dof; ++k) {
8451         if ((cind < cdof) && (k == cdofs[cind])) {
8452           /* Insert check for returning constrained indices */
8453           indices[*loff+k] = -(off+k+1);
8454           ++cind;
8455         } else {
8456           indices[*loff+k] = off+k-cind;
8457         }
8458       }
8459     } else {
8460       for (k = 0; k < dof; ++k) {
8461         if ((cind < cdof) && (k == cdofs[cind])) {
8462           /* Insert check for returning constrained indices */
8463           indices[*loff+dof-k-1] = -(off+k+1);
8464           ++cind;
8465         } else {
8466           indices[*loff+dof-k-1] = off+k-cind;
8467         }
8468       }
8469     }
8470   }
8471   *loff += dof;
8472   PetscFunctionReturn(0);
8473 }
8474 
8475 #undef __FUNCT__
8476 #define __FUNCT__ "indicesPointFields_private"
8477 /* . off - The global offset of this point */
8478 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8479 {
8480   PetscInt       numFields, foff, f;
8481   PetscErrorCode ierr;
8482 
8483   PetscFunctionBegin;
8484   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8485   for (f = 0, foff = 0; f < numFields; ++f) {
8486     PetscInt        fdof, fcomp, cfdof;
8487     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8488     PetscInt        cind = 0, k, c;
8489 
8490     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8491     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8492     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8493     if (!cfdof || setBC) {
8494       if (orientation >= 0) {
8495         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8496       } else {
8497         for (k = fdof/fcomp-1; k >= 0; --k) {
8498           for (c = 0; c < fcomp; ++c) {
8499             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8500           }
8501         }
8502       }
8503     } else {
8504       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8505       if (orientation >= 0) {
8506         for (k = 0; k < fdof; ++k) {
8507           if ((cind < cfdof) && (k == fcdofs[cind])) {
8508             indices[foffs[f]+k] = -(off+foff+k+1);
8509             ++cind;
8510           } else {
8511             indices[foffs[f]+k] = off+foff+k-cind;
8512           }
8513         }
8514       } else {
8515         for (k = fdof/fcomp-1; k >= 0; --k) {
8516           for (c = 0; c < fcomp; ++c) {
8517             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8518               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8519               ++cind;
8520             } else {
8521               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8522             }
8523           }
8524         }
8525       }
8526     }
8527     foff     += fdof - cfdof;
8528     foffs[f] += fdof;
8529   }
8530   PetscFunctionReturn(0);
8531 }
8532 
8533 #undef __FUNCT__
8534 #define __FUNCT__ "DMPlexMatSetClosure"
8535 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8536 {
8537   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8538   PetscInt      *points = NULL;
8539   PetscInt      *indices;
8540   PetscInt       offsets[32];
8541   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8542   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8543   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8544   PetscErrorCode ierr;
8545 
8546   PetscFunctionBegin;
8547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8548   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8549   if (useDefault) {
8550     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8551   }
8552   if (useGlobalDefault) {
8553     if (useDefault) {
8554       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8555     } else {
8556       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8557     }
8558   }
8559   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8560   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8561   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8562   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8563   /* Compress out points not in the section */
8564   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8565   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8566     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8567       points[q*2]   = points[p];
8568       points[q*2+1] = points[p+1];
8569       ++q;
8570     }
8571   }
8572   numPoints = q;
8573   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8574     PetscInt fdof;
8575 
8576     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8577     for (f = 0; f < numFields; ++f) {
8578       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8579       offsets[f+1] += fdof;
8580     }
8581     numIndices += dof;
8582   }
8583   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8584 
8585   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8586   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8587   if (numFields) {
8588     for (p = 0; p < numPoints*2; p += 2) {
8589       PetscInt o = points[p+1];
8590       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8591       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8592     }
8593   } else {
8594     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8595       PetscInt o = points[p+1];
8596       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8597       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8598     }
8599   }
8600   if (useGlobalDefault && !useDefault) {
8601     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8602   }
8603   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8604   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8605   if (ierr) {
8606     PetscMPIInt    rank;
8607     PetscErrorCode ierr2;
8608 
8609     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
8610     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8611     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8612     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8613     CHKERRQ(ierr);
8614   }
8615   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8616   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8617   PetscFunctionReturn(0);
8618 }
8619 
8620 #undef __FUNCT__
8621 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8622 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8623 {
8624   PetscSection       coordSection;
8625   Vec                coordinates;
8626   const PetscScalar *coords;
8627   const PetscInt     dim = 2;
8628   PetscInt           d, f;
8629   PetscErrorCode     ierr;
8630 
8631   PetscFunctionBegin;
8632   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8633   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8634   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8635   if (v0) {
8636     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8637   }
8638   if (J) {
8639     for (d = 0; d < dim; d++) {
8640       for (f = 0; f < dim; f++) {
8641         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8642       }
8643     }
8644     *detJ = J[0]*J[3] - J[1]*J[2];
8645 #if 0
8646     if (detJ < 0.0) {
8647       const PetscReal xLength = mesh->periodicity[0];
8648 
8649       if (xLength != 0.0) {
8650         PetscReal v0x = coords[0*dim+0];
8651 
8652         if (v0x == 0.0) v0x = v0[0] = xLength;
8653         for (f = 0; f < dim; f++) {
8654           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8655 
8656           J[0*dim+f] = 0.5*(px - v0x);
8657         }
8658       }
8659       detJ = J[0]*J[3] - J[1]*J[2];
8660     }
8661 #endif
8662     PetscLogFlops(8.0 + 3.0);
8663   }
8664   if (invJ) {
8665     const PetscReal invDet = 1.0/(*detJ);
8666 
8667     invJ[0] =  invDet*J[3];
8668     invJ[1] = -invDet*J[1];
8669     invJ[2] = -invDet*J[2];
8670     invJ[3] =  invDet*J[0];
8671     PetscLogFlops(5.0);
8672   }
8673   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8674   PetscFunctionReturn(0);
8675 }
8676 
8677 #undef __FUNCT__
8678 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8679 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8680 {
8681   PetscSection       coordSection;
8682   Vec                coordinates;
8683   const PetscScalar *coords;
8684   const PetscInt     dim = 2;
8685   PetscInt           d, f;
8686   PetscErrorCode     ierr;
8687 
8688   PetscFunctionBegin;
8689   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8690   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8691   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8692   if (v0) {
8693     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8694   }
8695   if (J) {
8696     for (d = 0; d < dim; d++) {
8697       for (f = 0; f < dim; f++) {
8698         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8699       }
8700     }
8701     *detJ = J[0]*J[3] - J[1]*J[2];
8702     PetscLogFlops(8.0 + 3.0);
8703   }
8704   if (invJ) {
8705     const PetscReal invDet = 1.0/(*detJ);
8706 
8707     invJ[0] =  invDet*J[3];
8708     invJ[1] = -invDet*J[1];
8709     invJ[2] = -invDet*J[2];
8710     invJ[3] =  invDet*J[0];
8711     PetscLogFlops(5.0);
8712   }
8713   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8714   PetscFunctionReturn(0);
8715 }
8716 
8717 #undef __FUNCT__
8718 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8719 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8720 {
8721   PetscSection       coordSection;
8722   Vec                coordinates;
8723   const PetscScalar *coords;
8724   const PetscInt     dim = 3;
8725   PetscInt           d, f;
8726   PetscErrorCode     ierr;
8727 
8728   PetscFunctionBegin;
8729   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8730   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8731   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8732   if (v0) {
8733     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8734   }
8735   if (J) {
8736     for (d = 0; d < dim; d++) {
8737       for (f = 0; f < dim; f++) {
8738         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8739       }
8740     }
8741     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8742     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8743              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8744              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8745     PetscLogFlops(18.0 + 12.0);
8746   }
8747   if (invJ) {
8748     const PetscReal invDet = 1.0/(*detJ);
8749 
8750     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8751     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8752     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8753     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8754     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8755     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8756     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8757     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8758     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8759     PetscLogFlops(37.0);
8760   }
8761   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8762   PetscFunctionReturn(0);
8763 }
8764 
8765 #undef __FUNCT__
8766 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8767 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8768 {
8769   PetscSection       coordSection;
8770   Vec                coordinates;
8771   const PetscScalar *coords;
8772   const PetscInt     dim = 3;
8773   PetscInt           d;
8774   PetscErrorCode     ierr;
8775 
8776   PetscFunctionBegin;
8777   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8778   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8779   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8780   if (v0) {
8781     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8782   }
8783   if (J) {
8784     for (d = 0; d < dim; d++) {
8785       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8786       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8787       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8788     }
8789     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8790              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8791              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8792     PetscLogFlops(18.0 + 12.0);
8793   }
8794   if (invJ) {
8795     const PetscReal invDet = -1.0/(*detJ);
8796 
8797     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8798     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8799     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8800     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8801     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8802     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8803     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8804     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8805     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8806     PetscLogFlops(37.0);
8807   }
8808   *detJ *= 8.0;
8809   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8810   PetscFunctionReturn(0);
8811 }
8812 
8813 #undef __FUNCT__
8814 #define __FUNCT__ "DMPlexComputeCellGeometry"
8815 /*@C
8816   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8817 
8818   Collective on DM
8819 
8820   Input Arguments:
8821 + dm   - the DM
8822 - cell - the cell
8823 
8824   Output Arguments:
8825 + v0   - the translation part of this affine transform
8826 . J    - the Jacobian of the transform to the reference element
8827 . invJ - the inverse of the Jacobian
8828 - detJ - the Jacobian determinant
8829 
8830   Level: advanced
8831 
8832 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8833 @*/
8834 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
8835 {
8836   PetscInt       dim, coneSize;
8837   PetscErrorCode ierr;
8838 
8839   PetscFunctionBegin;
8840   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8841   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8842   switch (dim) {
8843   case 2:
8844     switch (coneSize) {
8845     case 3:
8846       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8847       break;
8848     case 4:
8849       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8850       break;
8851     default:
8852       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8853     }
8854     break;
8855   case 3:
8856     switch (coneSize) {
8857     case 4:
8858       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8859       break;
8860     case 8:
8861       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8862       break;
8863     default:
8864       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
8865     }
8866     break;
8867   default:
8868     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8869   }
8870   PetscFunctionReturn(0);
8871 }
8872 
8873 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8874 {
8875   switch (i) {
8876   case 0:
8877     switch (j) {
8878     case 0: return 0;
8879     case 1:
8880       switch (k) {
8881       case 0: return 0;
8882       case 1: return 0;
8883       case 2: return 1;
8884       }
8885     case 2:
8886       switch (k) {
8887       case 0: return 0;
8888       case 1: return -1;
8889       case 2: return 0;
8890       }
8891     }
8892   case 1:
8893     switch (j) {
8894     case 0:
8895       switch (k) {
8896       case 0: return 0;
8897       case 1: return 0;
8898       case 2: return -1;
8899       }
8900     case 1: return 0;
8901     case 2:
8902       switch (k) {
8903       case 0: return 1;
8904       case 1: return 0;
8905       case 2: return 0;
8906       }
8907     }
8908   case 2:
8909     switch (j) {
8910     case 0:
8911       switch (k) {
8912       case 0: return 0;
8913       case 1: return 1;
8914       case 2: return 0;
8915       }
8916     case 1:
8917       switch (k) {
8918       case 0: return -1;
8919       case 1: return 0;
8920       case 2: return 0;
8921       }
8922     case 2: return 0;
8923     }
8924   }
8925   return 0;
8926 }
8927 
8928 #undef __FUNCT__
8929 #define __FUNCT__ "DMPlexCreateRigidBody"
8930 /*@C
8931   DMPlexCreateRigidBody - create rigid body modes from coordinates
8932 
8933   Collective on DM
8934 
8935   Input Arguments:
8936 + dm - the DM
8937 . section - the local section associated with the rigid field, or NULL for the default section
8938 - globalSection - the global section associated with the rigid field, or NULL for the default section
8939 
8940   Output Argument:
8941 . sp - the null space
8942 
8943   Note: This is necessary to take account of Dirichlet conditions on the displacements
8944 
8945   Level: advanced
8946 
8947 .seealso: MatNullSpaceCreate()
8948 @*/
8949 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8950 {
8951   MPI_Comm       comm;
8952   Vec            coordinates, localMode, mode[6];
8953   PetscSection   coordSection;
8954   PetscScalar   *coords;
8955   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8956   PetscErrorCode ierr;
8957 
8958   PetscFunctionBegin;
8959   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
8960   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8961   if (dim == 1) {
8962     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
8963     PetscFunctionReturn(0);
8964   }
8965   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8966   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8967   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8968   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8969   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8970   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8971   m    = (dim*(dim+1))/2;
8972   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8973   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8974   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8975   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8976   /* Assume P1 */
8977   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8978   for (d = 0; d < dim; ++d) {
8979     PetscScalar values[3] = {0.0, 0.0, 0.0};
8980 
8981     values[d] = 1.0;
8982     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
8983     for (v = vStart; v < vEnd; ++v) {
8984       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8985     }
8986     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8987     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8988   }
8989   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8990   for (d = dim; d < dim*(dim+1)/2; ++d) {
8991     PetscInt i, j, k = dim > 2 ? d - dim : d;
8992 
8993     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8994     for (v = vStart; v < vEnd; ++v) {
8995       PetscScalar values[3] = {0.0, 0.0, 0.0};
8996       PetscInt    off;
8997 
8998       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8999       for (i = 0; i < dim; ++i) {
9000         for (j = 0; j < dim; ++j) {
9001           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9002         }
9003       }
9004       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9005     }
9006     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9007     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9008   }
9009   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9010   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9011   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9012   /* Orthonormalize system */
9013   for (i = dim; i < m; ++i) {
9014     PetscScalar dots[6];
9015 
9016     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9017     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9018     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9019     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9020   }
9021   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9022   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9023   PetscFunctionReturn(0);
9024 }
9025 
9026 #undef __FUNCT__
9027 #define __FUNCT__ "DMPlexGetHybridBounds"
9028 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9029 {
9030   DM_Plex       *mesh = (DM_Plex*) dm->data;
9031   PetscInt       dim;
9032   PetscErrorCode ierr;
9033 
9034   PetscFunctionBegin;
9035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9036   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9037   if (cMax) *cMax = mesh->hybridPointMax[dim];
9038   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9039   if (eMax) *eMax = mesh->hybridPointMax[1];
9040   if (vMax) *vMax = mesh->hybridPointMax[0];
9041   PetscFunctionReturn(0);
9042 }
9043 
9044 #undef __FUNCT__
9045 #define __FUNCT__ "DMPlexSetHybridBounds"
9046 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9047 {
9048   DM_Plex       *mesh = (DM_Plex*) dm->data;
9049   PetscInt       dim;
9050   PetscErrorCode ierr;
9051 
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9054   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9055   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9056   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9057   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9058   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9059   PetscFunctionReturn(0);
9060 }
9061 
9062 #undef __FUNCT__
9063 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9064 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9065 {
9066   DM_Plex *mesh = (DM_Plex*) dm->data;
9067 
9068   PetscFunctionBegin;
9069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9070   PetscValidPointer(cellHeight, 2);
9071   *cellHeight = mesh->vtkCellHeight;
9072   PetscFunctionReturn(0);
9073 }
9074 
9075 #undef __FUNCT__
9076 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9077 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9078 {
9079   DM_Plex *mesh = (DM_Plex*) dm->data;
9080 
9081   PetscFunctionBegin;
9082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9083   mesh->vtkCellHeight = cellHeight;
9084   PetscFunctionReturn(0);
9085 }
9086 
9087 #undef __FUNCT__
9088 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9089 /* We can easily have a form that takes an IS instead */
9090 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9091 {
9092   PetscSection   section, globalSection;
9093   PetscInt      *numbers, p;
9094   PetscErrorCode ierr;
9095 
9096   PetscFunctionBegin;
9097   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9098   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9099   for (p = pStart; p < pEnd; ++p) {
9100     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9101   }
9102   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9103   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9104   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9105   for (p = pStart; p < pEnd; ++p) {
9106     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9107   }
9108   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9109   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9110   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9111   PetscFunctionReturn(0);
9112 }
9113 
9114 #undef __FUNCT__
9115 #define __FUNCT__ "DMPlexGetCellNumbering"
9116 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9117 {
9118   DM_Plex       *mesh = (DM_Plex*) dm->data;
9119   PetscInt       cellHeight, cStart, cEnd, cMax;
9120   PetscErrorCode ierr;
9121 
9122   PetscFunctionBegin;
9123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9124   if (!mesh->globalCellNumbers) {
9125     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9126     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9127     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9128     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9129     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9130   }
9131   *globalCellNumbers = mesh->globalCellNumbers;
9132   PetscFunctionReturn(0);
9133 }
9134 
9135 #undef __FUNCT__
9136 #define __FUNCT__ "DMPlexGetVertexNumbering"
9137 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9138 {
9139   DM_Plex       *mesh = (DM_Plex*) dm->data;
9140   PetscInt       vStart, vEnd, vMax;
9141   PetscErrorCode ierr;
9142 
9143   PetscFunctionBegin;
9144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9145   if (!mesh->globalVertexNumbers) {
9146     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9147     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9148     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9149     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9150   }
9151   *globalVertexNumbers = mesh->globalVertexNumbers;
9152   PetscFunctionReturn(0);
9153 }
9154 
9155 #undef __FUNCT__
9156 #define __FUNCT__ "DMPlexGetScale"
9157 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9158 {
9159   DM_Plex *mesh = (DM_Plex*) dm->data;
9160 
9161   PetscFunctionBegin;
9162   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9163   PetscValidPointer(scale, 3);
9164   *scale = mesh->scale[unit];
9165   PetscFunctionReturn(0);
9166 }
9167 
9168 #undef __FUNCT__
9169 #define __FUNCT__ "DMPlexSetScale"
9170 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9171 {
9172   DM_Plex *mesh = (DM_Plex*) dm->data;
9173 
9174   PetscFunctionBegin;
9175   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9176   mesh->scale[unit] = scale;
9177   PetscFunctionReturn(0);
9178 }
9179 
9180 
9181 /*******************************************************************************
9182 This should be in a separate Discretization object, but I am not sure how to lay
9183 it out yet, so I am stuffing things here while I experiment.
9184 *******************************************************************************/
9185 #undef __FUNCT__
9186 #define __FUNCT__ "DMPlexSetFEMIntegration"
9187 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9188                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9189                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9190                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9191                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9192                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9193                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9194                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9195                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9196                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9197                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9198                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9199                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9200                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9201                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9202                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9203                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9204 {
9205   DM_Plex *mesh = (DM_Plex*) dm->data;
9206 
9207   PetscFunctionBegin;
9208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9209   mesh->integrateResidualFEM       = integrateResidualFEM;
9210   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9211   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9212   PetscFunctionReturn(0);
9213 }
9214 
9215 #undef __FUNCT__
9216 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9217 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9218 {
9219   Vec            coordinates;
9220   PetscSection   section, cSection;
9221   PetscInt       dim, vStart, vEnd, v, c, d;
9222   PetscScalar   *values, *cArray;
9223   PetscReal     *coords;
9224   PetscErrorCode ierr;
9225 
9226   PetscFunctionBegin;
9227   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9228   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9229   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9230   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9231   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9232   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9233   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9234   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9235   for (v = vStart; v < vEnd; ++v) {
9236     PetscInt dof, off;
9237 
9238     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9239     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9240     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9241     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9242     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9243     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9244   }
9245   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9246   /* Temporary, must be replaced by a projection on the finite element basis */
9247   {
9248     PetscInt eStart = 0, eEnd = 0, e, depth;
9249 
9250     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9251     --depth;
9252     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9253     for (e = eStart; e < eEnd; ++e) {
9254       const PetscInt *cone = NULL;
9255       PetscInt        coneSize, d;
9256       PetscScalar    *coordsA, *coordsB;
9257 
9258       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9259       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9260       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9261       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9262       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9263       for (d = 0; d < dim; ++d) {
9264         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9265       }
9266       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9267       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9268     }
9269   }
9270 
9271   ierr = PetscFree(coords);CHKERRQ(ierr);
9272   ierr = PetscFree(values);CHKERRQ(ierr);
9273 #if 0
9274   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9275   PetscReal      detJ;
9276 
9277   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9278   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9279   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9280 
9281   for (PetscInt c = cStart; c < cEnd; ++c) {
9282     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9283     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9284     const int                          oSize   = pV.getSize();
9285     int                                v       = 0;
9286 
9287     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9288     for (PetscInt cl = 0; cl < oSize; ++cl) {
9289       const PetscInt fDim;
9290 
9291       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9292       if (pointDim) {
9293         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9294           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9295         }
9296       }
9297     }
9298     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9299     pV.clear();
9300   }
9301   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9302   ierr = PetscFree(values);CHKERRQ(ierr);
9303 #endif
9304   PetscFunctionReturn(0);
9305 }
9306 
9307 #undef __FUNCT__
9308 #define __FUNCT__ "DMPlexProjectFunction"
9309 /*@C
9310   DMPlexProjectFunction - This projects the given function into the function space provided.
9311 
9312   Input Parameters:
9313 + dm      - The DM
9314 . numComp - The number of components (functions)
9315 . funcs   - The coordinate functions to evaluate
9316 - mode    - The insertion mode for values
9317 
9318   Output Parameter:
9319 . X - vector
9320 
9321   Level: developer
9322 
9323   Note:
9324   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9325   We will eventually fix it.
9326 
9327 ,seealso: DMPlexComputeL2Diff()
9328 */
9329 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9330 {
9331   Vec            localX;
9332   PetscErrorCode ierr;
9333 
9334   PetscFunctionBegin;
9335   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9336   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9337   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9338   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9339   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9340   PetscFunctionReturn(0);
9341 }
9342 
9343 #undef __FUNCT__
9344 #define __FUNCT__ "DMPlexComputeL2Diff"
9345 /*@C
9346   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9347 
9348   Input Parameters:
9349 + dm    - The DM
9350 . quad  - The PetscQuadrature object for each field
9351 . funcs - The functions to evaluate for each field component
9352 - X     - The coefficient vector u_h
9353 
9354   Output Parameter:
9355 . diff - The diff ||u - u_h||_2
9356 
9357   Level: developer
9358 
9359 .seealso: DMPlexProjectFunction()
9360 */
9361 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9362 {
9363   const PetscInt debug = 0;
9364   PetscSection   section;
9365   Vec            localX;
9366   PetscReal     *coords, *v0, *J, *invJ, detJ;
9367   PetscReal      localDiff = 0.0;
9368   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9369   PetscErrorCode ierr;
9370 
9371   PetscFunctionBegin;
9372   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9373   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9374   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9375   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9376   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9377   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9378   for (field = 0; field < numFields; ++field) {
9379     numComponents += quad[field].numComponents;
9380   }
9381   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9382   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9383   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9384   for (c = cStart; c < cEnd; ++c) {
9385     const PetscScalar *x;
9386     PetscReal          elemDiff = 0.0;
9387 
9388     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9389     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9390     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9391 
9392     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9393       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9394       const PetscReal *quadPoints    = quad[field].quadPoints;
9395       const PetscReal *quadWeights   = quad[field].quadWeights;
9396       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9397       const PetscInt   numBasisComps = quad[field].numComponents;
9398       const PetscReal *basis         = quad[field].basis;
9399       PetscInt         q, d, e, fc, f;
9400 
9401       if (debug) {
9402         char title[1024];
9403         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9404         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9405       }
9406       for (q = 0; q < numQuadPoints; ++q) {
9407         for (d = 0; d < dim; d++) {
9408           coords[d] = v0[d];
9409           for (e = 0; e < dim; e++) {
9410             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9411           }
9412         }
9413         for (fc = 0; fc < numBasisComps; ++fc) {
9414           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9415           PetscReal       interpolant = 0.0;
9416           for (f = 0; f < numBasisFuncs; ++f) {
9417             const PetscInt fidx = f*numBasisComps+fc;
9418             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9419           }
9420           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9421           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9422         }
9423       }
9424       comp        += numBasisComps;
9425       fieldOffset += numBasisFuncs*numBasisComps;
9426     }
9427     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9428     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9429     localDiff += elemDiff;
9430   }
9431   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9432   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9433   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9434   *diff = PetscSqrtReal(*diff);
9435   PetscFunctionReturn(0);
9436 }
9437 
9438 #undef __FUNCT__
9439 #define __FUNCT__ "DMPlexComputeResidualFEM"
9440 /*@
9441   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9442 
9443   Input Parameters:
9444 + dm - The mesh
9445 . X  - Local input vector
9446 - user - The user context
9447 
9448   Output Parameter:
9449 . F  - Local output vector
9450 
9451   Note:
9452   The second member of the user context must be an FEMContext.
9453 
9454   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9455   like a GPU, or vectorize on a multicore machine.
9456 
9457 .seealso: DMPlexComputeJacobianActionFEM()
9458 */
9459 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9460 {
9461   DM_Plex         *mesh = (DM_Plex*) dm->data;
9462   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9463   PetscQuadrature *quad = fem->quad;
9464   PetscSection     section;
9465   PetscReal       *v0, *J, *invJ, *detJ;
9466   PetscScalar     *elemVec, *u;
9467   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9468   PetscInt         cellDof = 0, numComponents = 0;
9469   PetscErrorCode   ierr;
9470 
9471   PetscFunctionBegin;
9472   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9473   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9474   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9475   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9476   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9477   numCells = cEnd - cStart;
9478   for (field = 0; field < numFields; ++field) {
9479     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9480     numComponents += quad[field].numComponents;
9481   }
9482   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9483   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9484   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);
9485   for (c = cStart; c < cEnd; ++c) {
9486     const PetscScalar *x;
9487     PetscInt           i;
9488 
9489     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9490     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9491     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9492 
9493     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9494     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9495   }
9496   for (field = 0; field < numFields; ++field) {
9497     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9498     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9499     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9500     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9501     /* Conforming batches */
9502     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9503     PetscInt numBlocks  = 1;
9504     PetscInt batchSize  = numBlocks * blockSize;
9505     PetscInt numBatches = numBatchesTmp;
9506     PetscInt numChunks  = numCells / (numBatches*batchSize);
9507     /* Remainder */
9508     PetscInt numRemainder = numCells % (numBatches * batchSize);
9509     PetscInt offset       = numCells - numRemainder;
9510 
9511     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9512     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9513                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9514   }
9515   for (c = cStart; c < cEnd; ++c) {
9516     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9517     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9518   }
9519   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9520   if (mesh->printFEM) {
9521     PetscMPIInt rank, numProcs;
9522     PetscInt    p;
9523 
9524     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9525     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9526     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9527     for (p = 0; p < numProcs; ++p) {
9528       if (p == rank) {
9529         Vec f;
9530 
9531         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9532         ierr = VecCopy(F, f);CHKERRQ(ierr);
9533         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9534         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9535         ierr = VecDestroy(&f);CHKERRQ(ierr);
9536         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9537       }
9538       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9539     }
9540   }
9541   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9542   PetscFunctionReturn(0);
9543 }
9544 
9545 #undef __FUNCT__
9546 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9547 /*@C
9548   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9549 
9550   Input Parameters:
9551 + dm - The mesh
9552 . J  - The Jacobian shell matrix
9553 . X  - Local input vector
9554 - user - The user context
9555 
9556   Output Parameter:
9557 . F  - Local output vector
9558 
9559   Note:
9560   The second member of the user context must be an FEMContext.
9561 
9562   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9563   like a GPU, or vectorize on a multicore machine.
9564 
9565 .seealso: DMPlexComputeResidualFEM()
9566 */
9567 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9568 {
9569   DM_Plex         *mesh = (DM_Plex*) dm->data;
9570   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9571   PetscQuadrature *quad = fem->quad;
9572   PetscSection     section;
9573   JacActionCtx    *jctx;
9574   PetscReal       *v0, *J, *invJ, *detJ;
9575   PetscScalar     *elemVec, *u, *a;
9576   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9577   PetscInt         cellDof = 0;
9578   PetscErrorCode   ierr;
9579 
9580   PetscFunctionBegin;
9581   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9582   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9583   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9584   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9585   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9586   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9587   numCells = cEnd - cStart;
9588   for (field = 0; field < numFields; ++field) {
9589     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9590   }
9591   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9592   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);
9593   for (c = cStart; c < cEnd; ++c) {
9594     const PetscScalar *x;
9595     PetscInt           i;
9596 
9597     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9598     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9599     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9600     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9601     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9602     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9603     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9604     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9605   }
9606   for (field = 0; field < numFields; ++field) {
9607     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9608     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9609     /* Conforming batches */
9610     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9611     PetscInt numBlocks  = 1;
9612     PetscInt batchSize  = numBlocks * blockSize;
9613     PetscInt numBatches = numBatchesTmp;
9614     PetscInt numChunks  = numCells / (numBatches*batchSize);
9615     /* Remainder */
9616     PetscInt numRemainder = numCells % (numBatches * batchSize);
9617     PetscInt offset       = numCells - numRemainder;
9618 
9619     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);
9620     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],
9621                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9622   }
9623   for (c = cStart; c < cEnd; ++c) {
9624     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9625     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9626   }
9627   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9628   if (mesh->printFEM) {
9629     PetscMPIInt rank, numProcs;
9630     PetscInt    p;
9631 
9632     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9633     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9634     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9635     for (p = 0; p < numProcs; ++p) {
9636       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9637       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9638     }
9639   }
9640   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9641   PetscFunctionReturn(0);
9642 }
9643 
9644 #undef __FUNCT__
9645 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9646 /*@
9647   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9648 
9649   Input Parameters:
9650 + dm - The mesh
9651 . X  - Local input vector
9652 - user - The user context
9653 
9654   Output Parameter:
9655 . Jac  - Jacobian matrix
9656 
9657   Note:
9658   The second member of the user context must be an FEMContext.
9659 
9660   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9661   like a GPU, or vectorize on a multicore machine.
9662 
9663 .seealso: FormFunctionLocal()
9664 */
9665 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9666 {
9667   DM_Plex         *mesh = (DM_Plex*) dm->data;
9668   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9669   PetscQuadrature *quad = fem->quad;
9670   PetscSection     section;
9671   PetscReal       *v0, *J, *invJ, *detJ;
9672   PetscScalar     *elemMat, *u;
9673   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9674   PetscInt         cellDof = 0, numComponents = 0;
9675   PetscBool        isShell;
9676   PetscErrorCode   ierr;
9677 
9678   PetscFunctionBegin;
9679   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9680   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9681   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9682   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9683   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9684   numCells = cEnd - cStart;
9685   for (field = 0; field < numFields; ++field) {
9686     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9687     numComponents += quad[field].numComponents;
9688   }
9689   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9690   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9691   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);
9692   for (c = cStart; c < cEnd; ++c) {
9693     const PetscScalar *x;
9694     PetscInt           i;
9695 
9696     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9697     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9698     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9699 
9700     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9701     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9702   }
9703   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9704   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9705     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9706     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9707     PetscInt       fieldJ;
9708 
9709     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9710       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9711       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9712       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9713       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9714       /* Conforming batches */
9715       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9716       PetscInt numBlocks  = 1;
9717       PetscInt batchSize  = numBlocks * blockSize;
9718       PetscInt numBatches = numBatchesTmp;
9719       PetscInt numChunks  = numCells / (numBatches*batchSize);
9720       /* Remainder */
9721       PetscInt numRemainder = numCells % (numBatches * batchSize);
9722       PetscInt offset       = numCells - numRemainder;
9723 
9724       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9725       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9726                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9727     }
9728   }
9729   for (c = cStart; c < cEnd; ++c) {
9730     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9731     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9732   }
9733   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9734 
9735   /* Assemble matrix, using the 2-step process:
9736        MatAssemblyBegin(), MatAssemblyEnd(). */
9737   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9738   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9739 
9740   if (mesh->printFEM) {
9741     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9742     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9743     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9744   }
9745   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9746   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9747   if (isShell) {
9748     JacActionCtx *jctx;
9749 
9750     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9751     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9752   }
9753   *str = SAME_NONZERO_PATTERN;
9754   PetscFunctionReturn(0);
9755 }
9756 
9757 
9758 #undef __FUNCT__
9759 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9760 /*@C
9761   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9762   the local section and an SF describing the section point overlap.
9763 
9764   Input Parameters:
9765   + s - The PetscSection for the local field layout
9766   . sf - The SF describing parallel layout of the section points
9767   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9768   . label - The label specifying the points
9769   - labelValue - The label stratum specifying the points
9770 
9771   Output Parameter:
9772   . gsection - The PetscSection for the global field layout
9773 
9774   Note: This gives negative sizes and offsets to points not owned by this process
9775 
9776   Level: developer
9777 
9778 .seealso: PetscSectionCreate()
9779 @*/
9780 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9781 {
9782   PetscInt      *neg;
9783   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9784   PetscErrorCode ierr;
9785 
9786   PetscFunctionBegin;
9787   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9788   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9789   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9790   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9791   /* Mark ghost points with negative dof */
9792   for (p = pStart; p < pEnd; ++p) {
9793     PetscInt value;
9794 
9795     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9796     if (value != labelValue) continue;
9797     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9798     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9799     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9800     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9801     neg[p-pStart] = -(dof+1);
9802   }
9803   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9804   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
9805   if (nroots >= 0) {
9806     if (nroots > pEnd - pStart) {
9807       PetscInt *tmpDof;
9808       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9809       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9810       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9811       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9812       for (p = pStart; p < pEnd; ++p) {
9813         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
9814       }
9815       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9816     } else {
9817       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9818       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9819     }
9820   }
9821   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9822   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9823     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9824 
9825     (*gsection)->atlasOff[p] = off;
9826 
9827     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9828   }
9829   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9830   globalOff -= off;
9831   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9832     (*gsection)->atlasOff[p] += globalOff;
9833 
9834     neg[p] = -((*gsection)->atlasOff[p]+1);
9835   }
9836   /* Put in negative offsets for ghost points */
9837   if (nroots >= 0) {
9838     if (nroots > pEnd - pStart) {
9839       PetscInt *tmpOff;
9840       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9841       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9842       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9843       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9844       for (p = pStart; p < pEnd; ++p) {
9845         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
9846       }
9847       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9848     } else {
9849       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9850       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9851     }
9852   }
9853   ierr = PetscFree(neg);CHKERRQ(ierr);
9854   PetscFunctionReturn(0);
9855 }
9856