xref: /petsc/src/dm/impls/plex/plex.c (revision d53a3d6fea7331c598f751e9a4893fffdfd7b7a2)
1 #include <petsc-private/pleximpl.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(((PetscObject) v)->comm, 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(((PetscObject) dm)->comm, 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(((PetscObject) v)->comm, 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(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &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(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &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(((PetscObject) dm)->comm, 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 = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   }
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex       *mesh = (DM_Plex*) dm->data;
344   DMLabel        next  = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) PetscFunctionReturn(0);
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = NULL;
374   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star  = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex*) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex           *mesh = (DM_Plex*) dm->data;
459   MPI_Comm           comm  = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514 
515   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
516   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
517 
518   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
519 
520   /*
521    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
522     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
523        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
524     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
525        Create sfAdj connecting rootSectionAdj and leafSectionAdj
526     3. Visit unowned points on interface, write adjacencies to adj
527        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
528     4. Visit owned points on interface, write adjacencies to rootAdj
529        Remove redundancy in rootAdj
530    ** The last two traversals use transitive closure
531     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
532        Allocate memory addressed by sectionAdj (cols)
533     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
534    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
535   */
536 
537   for (l = 0; l < nleaves; ++l) {
538     PetscInt dof, off, d, q;
539     PetscInt p = leaves[l], numAdj = maxAdjSize;
540 
541     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
542     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
543     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
544     for (q = 0; q < numAdj; ++q) {
545       PetscInt ndof, ncdof;
546 
547       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
548       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
549       for (d = off; d < off+dof; ++d) {
550         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
551       }
552     }
553   }
554   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
555   if (debug) {
556     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
557     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
558   }
559   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
560   if (size > 1) {
561     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
562     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
563   }
564   if (debug) {
565     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
566     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
567   }
568   /* Add in local adjacency sizes for owned dofs on interface (roots) */
569   for (p = pStart; p < pEnd; ++p) {
570     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
571 
572     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
573     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
574     if (!dof) continue;
575     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
576     if (adof <= 0) continue;
577     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
578     for (q = 0; q < numAdj; ++q) {
579       PetscInt ndof, ncdof;
580 
581       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
582       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
583       for (d = off; d < off+dof; ++d) {
584         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
585       }
586     }
587   }
588   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
589   if (debug) {
590     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
591     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
592   }
593   /* Create adj SF based on dof SF */
594   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
595   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
596   if (debug) {
597     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
598     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
599   }
600   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
601   /* Create leaf adjacency */
602   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
603   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
604   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
605   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
606   for (l = 0; l < nleaves; ++l) {
607     PetscInt dof, off, d, q;
608     PetscInt p = leaves[l], numAdj = maxAdjSize;
609 
610     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
611     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
612     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
613     for (d = off; d < off+dof; ++d) {
614       PetscInt aoff, i = 0;
615 
616       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
617       for (q = 0; q < numAdj; ++q) {
618         PetscInt ndof, ncdof, ngoff, nd;
619 
620         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
621         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
622         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
623         for (nd = 0; nd < ndof-ncdof; ++nd) {
624           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
625           ++i;
626         }
627       }
628     }
629   }
630   /* Debugging */
631   if (debug) {
632     IS tmp;
633     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
634     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
635     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
636   }
637   /* Gather adjacenct indices to root */
638   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
639   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
640   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
812         }
813       }
814       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);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt       numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) ++dnzu[r-rStart];
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) ++onzu[r-rStart];
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscInt       *tmpClosure,*tmpAdj,*visits;
900   PetscInt        c,cStart,cEnd,pStart,pEnd;
901   PetscErrorCode  ierr;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907 
908   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
909 
910   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
911   npoints = pEnd - pStart;
912 
913   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
914   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
915   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
916   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
917   for (c=cStart; c<cEnd; c++) {
918     PetscInt *support = tmpClosure;
919     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
920     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
921   }
922   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
924   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
926 
927   ierr = PetscSFGetRanks();CHKERRQ(ierr);
928 
929 
930   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
931   for (c=cStart; c<cEnd; c++) {
932     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
933     /*
934      Depth-first walk of transitive closure.
935      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.
936      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
937      */
938   }
939 
940   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
941   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 #endif
945 
946 #undef __FUNCT__
947 #define __FUNCT__ "DMCreateMatrix_Plex"
948 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
949 {
950   PetscSection   section, sectionGlobal;
951   PetscInt       bs = -1;
952   PetscInt       localSize;
953   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
954   PetscErrorCode ierr;
955 
956   PetscFunctionBegin;
957 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
958   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
959 #endif
960   if (!mtype) mtype = MATAIJ;
961   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
962   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
963   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
964   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
965   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
966   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
967   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
968   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
975   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
976   /* Check for symmetric storage */
977   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
978   if (isSymmetric) {
979     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
980   }
981   if (!isShell) {
982     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
983     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
984 
985     if (bs < 0) {
986       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
987         PetscInt pStart, pEnd, p, dof, cdof;
988 
989         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
990         for (p = pStart; p < pEnd; ++p) {
991           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
992           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
993           if (dof-cdof) {
994             if (bs < 0) {
995               bs = dof-cdof;
996             } else if (bs != dof-cdof) {
997               /* Layout does not admit a pointwise block size */
998               bs = 1;
999               break;
1000             }
1001           }
1002         }
1003         /* Must have same blocksize on all procs (some might have no points) */
1004         bsLocal = bs;
1005         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1006         bsLocal = bs < 0 ? bsMax : bs;
1007         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1008         if (bsMin != bsMax) {
1009           bs = 1;
1010         } else {
1011           bs = bsMax;
1012         }
1013       } else {
1014         bs = 1;
1015       }
1016     }
1017     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1018     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1020     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1021     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1022     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1023     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1024   }
1025   PetscFunctionReturn(0);
1026 }
1027 
1028 #undef __FUNCT__
1029 #define __FUNCT__ "DMPlexGetDimension"
1030 /*@
1031   DMPlexGetDimension - Return the topological mesh dimension
1032 
1033   Not collective
1034 
1035   Input Parameter:
1036 . mesh - The DMPlex
1037 
1038   Output Parameter:
1039 . dim - The topological mesh dimension
1040 
1041   Level: beginner
1042 
1043 .seealso: DMPlexCreate()
1044 @*/
1045 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1046 {
1047   DM_Plex *mesh = (DM_Plex*) dm->data;
1048 
1049   PetscFunctionBegin;
1050   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1051   PetscValidPointer(dim, 2);
1052   *dim = mesh->dim;
1053   PetscFunctionReturn(0);
1054 }
1055 
1056 #undef __FUNCT__
1057 #define __FUNCT__ "DMPlexSetDimension"
1058 /*@
1059   DMPlexSetDimension - Set the topological mesh dimension
1060 
1061   Collective on mesh
1062 
1063   Input Parameters:
1064 + mesh - The DMPlex
1065 - dim - The topological mesh dimension
1066 
1067   Level: beginner
1068 
1069 .seealso: DMPlexCreate()
1070 @*/
1071 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1072 {
1073   DM_Plex *mesh = (DM_Plex*) dm->data;
1074 
1075   PetscFunctionBegin;
1076   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1077   PetscValidLogicalCollectiveInt(dm, dim, 2);
1078   mesh->dim               = dim;
1079   mesh->preallocCenterDim = dim;
1080   PetscFunctionReturn(0);
1081 }
1082 
1083 #undef __FUNCT__
1084 #define __FUNCT__ "DMPlexGetChart"
1085 /*@
1086   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1087 
1088   Not collective
1089 
1090   Input Parameter:
1091 . mesh - The DMPlex
1092 
1093   Output Parameters:
1094 + pStart - The first mesh point
1095 - pEnd   - The upper bound for mesh points
1096 
1097   Level: beginner
1098 
1099 .seealso: DMPlexCreate(), DMPlexSetChart()
1100 @*/
1101 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1102 {
1103   DM_Plex       *mesh = (DM_Plex*) dm->data;
1104   PetscErrorCode ierr;
1105 
1106   PetscFunctionBegin;
1107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1108   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1109   PetscFunctionReturn(0);
1110 }
1111 
1112 #undef __FUNCT__
1113 #define __FUNCT__ "DMPlexSetChart"
1114 /*@
1115   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1116 
1117   Not collective
1118 
1119   Input Parameters:
1120 + mesh - The DMPlex
1121 . pStart - The first mesh point
1122 - pEnd   - The upper bound for mesh points
1123 
1124   Output Parameters:
1125 
1126   Level: beginner
1127 
1128 .seealso: DMPlexCreate(), DMPlexGetChart()
1129 @*/
1130 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1131 {
1132   DM_Plex       *mesh = (DM_Plex*) dm->data;
1133   PetscErrorCode ierr;
1134 
1135   PetscFunctionBegin;
1136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1137   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1138   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1139   PetscFunctionReturn(0);
1140 }
1141 
1142 #undef __FUNCT__
1143 #define __FUNCT__ "DMPlexGetConeSize"
1144 /*@
1145   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1146 
1147   Not collective
1148 
1149   Input Parameters:
1150 + mesh - The DMPlex
1151 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1152 
1153   Output Parameter:
1154 . size - The cone size for point p
1155 
1156   Level: beginner
1157 
1158 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1159 @*/
1160 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1161 {
1162   DM_Plex       *mesh = (DM_Plex*) dm->data;
1163   PetscErrorCode ierr;
1164 
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1167   PetscValidPointer(size, 3);
1168   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1169   PetscFunctionReturn(0);
1170 }
1171 
1172 #undef __FUNCT__
1173 #define __FUNCT__ "DMPlexSetConeSize"
1174 /*@
1175   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1176 
1177   Not collective
1178 
1179   Input Parameters:
1180 + mesh - The DMPlex
1181 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1182 - size - The cone size for point p
1183 
1184   Output Parameter:
1185 
1186   Note:
1187   This should be called after DMPlexSetChart().
1188 
1189   Level: beginner
1190 
1191 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1192 @*/
1193 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1194 {
1195   DM_Plex       *mesh = (DM_Plex*) dm->data;
1196   PetscErrorCode ierr;
1197 
1198   PetscFunctionBegin;
1199   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1200   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1201 
1202   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1203   PetscFunctionReturn(0);
1204 }
1205 
1206 #undef __FUNCT__
1207 #define __FUNCT__ "DMPlexGetCone"
1208 /*@C
1209   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1210 
1211   Not collective
1212 
1213   Input Parameters:
1214 + mesh - The DMPlex
1215 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1216 
1217   Output Parameter:
1218 . cone - An array of points which are on the in-edges for point p
1219 
1220   Level: beginner
1221 
1222   Note:
1223   This routine is not available in Fortran.
1224 
1225 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1226 @*/
1227 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1228 {
1229   DM_Plex       *mesh = (DM_Plex*) dm->data;
1230   PetscInt       off;
1231   PetscErrorCode ierr;
1232 
1233   PetscFunctionBegin;
1234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1235   PetscValidPointer(cone, 3);
1236   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1237   *cone = &mesh->cones[off];
1238   PetscFunctionReturn(0);
1239 }
1240 
1241 #undef __FUNCT__
1242 #define __FUNCT__ "DMPlexSetCone"
1243 /*@
1244   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1245 
1246   Not collective
1247 
1248   Input Parameters:
1249 + mesh - The DMPlex
1250 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1251 - cone - An array of points which are on the in-edges for point p
1252 
1253   Output Parameter:
1254 
1255   Note:
1256   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1257 
1258   Level: beginner
1259 
1260 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1261 @*/
1262 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1263 {
1264   DM_Plex       *mesh = (DM_Plex*) dm->data;
1265   PetscInt       pStart, pEnd;
1266   PetscInt       dof, off, c;
1267   PetscErrorCode ierr;
1268 
1269   PetscFunctionBegin;
1270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1271   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1272   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1273   if (dof) PetscValidPointer(cone, 3);
1274   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1275   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1276   for (c = 0; c < dof; ++c) {
1277     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1278     mesh->cones[off+c] = cone[c];
1279   }
1280   PetscFunctionReturn(0);
1281 }
1282 
1283 #undef __FUNCT__
1284 #define __FUNCT__ "DMPlexGetConeOrientation"
1285 /*@C
1286   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1287 
1288   Not collective
1289 
1290   Input Parameters:
1291 + mesh - The DMPlex
1292 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1293 
1294   Output Parameter:
1295 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1296                     integer giving the prescription for cone traversal. If it is negative, the cone is
1297                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1298                     the index of the cone point on which to start.
1299 
1300   Level: beginner
1301 
1302   Note:
1303   This routine is not available in Fortran.
1304 
1305 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1306 @*/
1307 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1308 {
1309   DM_Plex       *mesh = (DM_Plex*) dm->data;
1310   PetscInt       off;
1311   PetscErrorCode ierr;
1312 
1313   PetscFunctionBegin;
1314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1315 #if defined(PETSC_USE_DEBUG)
1316   {
1317     PetscInt dof;
1318     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1319     if (dof) PetscValidPointer(coneOrientation, 3);
1320   }
1321 #endif
1322   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1323 
1324   *coneOrientation = &mesh->coneOrientations[off];
1325   PetscFunctionReturn(0);
1326 }
1327 
1328 #undef __FUNCT__
1329 #define __FUNCT__ "DMPlexSetConeOrientation"
1330 /*@
1331   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1332 
1333   Not collective
1334 
1335   Input Parameters:
1336 + mesh - The DMPlex
1337 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1338 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1339                     integer giving the prescription for cone traversal. If it is negative, the cone is
1340                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1341                     the index of the cone point on which to start.
1342 
1343   Output Parameter:
1344 
1345   Note:
1346   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1347 
1348   Level: beginner
1349 
1350 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1351 @*/
1352 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1353 {
1354   DM_Plex       *mesh = (DM_Plex*) dm->data;
1355   PetscInt       pStart, pEnd;
1356   PetscInt       dof, off, c;
1357   PetscErrorCode ierr;
1358 
1359   PetscFunctionBegin;
1360   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1361   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1362   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1363   if (dof) PetscValidPointer(coneOrientation, 3);
1364   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1365   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1366   for (c = 0; c < dof; ++c) {
1367     PetscInt cdof, o = coneOrientation[c];
1368 
1369     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1370     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1371     mesh->coneOrientations[off+c] = o;
1372   }
1373   PetscFunctionReturn(0);
1374 }
1375 
1376 #undef __FUNCT__
1377 #define __FUNCT__ "DMPlexInsertCone"
1378 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1379 {
1380   DM_Plex       *mesh = (DM_Plex*) dm->data;
1381   PetscInt       pStart, pEnd;
1382   PetscInt       dof, off;
1383   PetscErrorCode ierr;
1384 
1385   PetscFunctionBegin;
1386   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1387   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1388   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1389   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1390   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1391   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1392   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1393   mesh->cones[off+conePos] = conePoint;
1394   PetscFunctionReturn(0);
1395 }
1396 
1397 #undef __FUNCT__
1398 #define __FUNCT__ "DMPlexGetSupportSize"
1399 /*@
1400   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1401 
1402   Not collective
1403 
1404   Input Parameters:
1405 + mesh - The DMPlex
1406 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1407 
1408   Output Parameter:
1409 . size - The support size for point p
1410 
1411   Level: beginner
1412 
1413 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1414 @*/
1415 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1416 {
1417   DM_Plex       *mesh = (DM_Plex*) dm->data;
1418   PetscErrorCode ierr;
1419 
1420   PetscFunctionBegin;
1421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1422   PetscValidPointer(size, 3);
1423   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1424   PetscFunctionReturn(0);
1425 }
1426 
1427 #undef __FUNCT__
1428 #define __FUNCT__ "DMPlexSetSupportSize"
1429 /*@
1430   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1431 
1432   Not collective
1433 
1434   Input Parameters:
1435 + mesh - The DMPlex
1436 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1437 - size - The support size for point p
1438 
1439   Output Parameter:
1440 
1441   Note:
1442   This should be called after DMPlexSetChart().
1443 
1444   Level: beginner
1445 
1446 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1447 @*/
1448 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1449 {
1450   DM_Plex       *mesh = (DM_Plex*) dm->data;
1451   PetscErrorCode ierr;
1452 
1453   PetscFunctionBegin;
1454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1455   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1456 
1457   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1458   PetscFunctionReturn(0);
1459 }
1460 
1461 #undef __FUNCT__
1462 #define __FUNCT__ "DMPlexGetSupport"
1463 /*@C
1464   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1465 
1466   Not collective
1467 
1468   Input Parameters:
1469 + mesh - The DMPlex
1470 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1471 
1472   Output Parameter:
1473 . support - An array of points which are on the out-edges for point p
1474 
1475   Level: beginner
1476 
1477 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1478 @*/
1479 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1480 {
1481   DM_Plex       *mesh = (DM_Plex*) dm->data;
1482   PetscInt       off;
1483   PetscErrorCode ierr;
1484 
1485   PetscFunctionBegin;
1486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1487   PetscValidPointer(support, 3);
1488   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1489   *support = &mesh->supports[off];
1490   PetscFunctionReturn(0);
1491 }
1492 
1493 #undef __FUNCT__
1494 #define __FUNCT__ "DMPlexSetSupport"
1495 /*@
1496   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1497 
1498   Not collective
1499 
1500   Input Parameters:
1501 + mesh - The DMPlex
1502 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1503 - support - An array of points which are on the in-edges for point p
1504 
1505   Output Parameter:
1506 
1507   Note:
1508   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1509 
1510   Level: beginner
1511 
1512 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1513 @*/
1514 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1515 {
1516   DM_Plex       *mesh = (DM_Plex*) dm->data;
1517   PetscInt       pStart, pEnd;
1518   PetscInt       dof, off, c;
1519   PetscErrorCode ierr;
1520 
1521   PetscFunctionBegin;
1522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1523   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1524   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1525   if (dof) PetscValidPointer(support, 3);
1526   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1527   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1528   for (c = 0; c < dof; ++c) {
1529     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1530     mesh->supports[off+c] = support[c];
1531   }
1532   PetscFunctionReturn(0);
1533 }
1534 
1535 #undef __FUNCT__
1536 #define __FUNCT__ "DMPlexInsertSupport"
1537 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1538 {
1539   DM_Plex       *mesh = (DM_Plex*) dm->data;
1540   PetscInt       pStart, pEnd;
1541   PetscInt       dof, off;
1542   PetscErrorCode ierr;
1543 
1544   PetscFunctionBegin;
1545   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1546   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1547   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1548   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1549   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1550   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1551   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1552   mesh->supports[off+supportPos] = supportPoint;
1553   PetscFunctionReturn(0);
1554 }
1555 
1556 #undef __FUNCT__
1557 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1558 /*@C
1559   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1560 
1561   Not collective
1562 
1563   Input Parameters:
1564 + mesh - The DMPlex
1565 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1566 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1567 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1568 
1569   Output Parameters:
1570 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1571 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1572 
1573   Note:
1574   If using internal storage (points is NULL on input), each call overwrites the last output.
1575 
1576   Level: beginner
1577 
1578 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1579 @*/
1580 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1581 {
1582   DM_Plex        *mesh = (DM_Plex*) dm->data;
1583   PetscInt       *closure, *fifo;
1584   const PetscInt *tmp = NULL, *tmpO = NULL;
1585   PetscInt        tmpSize, t;
1586   PetscInt        depth       = 0, maxSize;
1587   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1588   PetscErrorCode  ierr;
1589 
1590   PetscFunctionBegin;
1591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1592   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1593   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1594   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1595   if (*points) {
1596     closure = *points;
1597   } else {
1598     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1599   }
1600   closure[0] = p; closure[1] = 0;
1601   /* This is only 1-level */
1602   if (useCone) {
1603     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1604     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1605     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1606   } else {
1607     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1608     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1609   }
1610   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1611     const PetscInt cp = tmp[t];
1612     const PetscInt co = tmpO ? tmpO[t] : 0;
1613 
1614     closure[closureSize]   = cp;
1615     closure[closureSize+1] = co;
1616     fifo[fifoSize]         = cp;
1617     fifo[fifoSize+1]       = co;
1618   }
1619   while (fifoSize - fifoStart) {
1620     const PetscInt q   = fifo[fifoStart];
1621     const PetscInt o   = fifo[fifoStart+1];
1622     const PetscInt rev = o >= 0 ? 0 : 1;
1623     const PetscInt off = rev ? -(o+1) : o;
1624 
1625     if (useCone) {
1626       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1627       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1628       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1629     } else {
1630       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1631       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1632       tmpO = NULL;
1633     }
1634     for (t = 0; t < tmpSize; ++t) {
1635       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1636       const PetscInt cp = tmp[i];
1637       /* Must propogate orientation */
1638       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1639       PetscInt       c;
1640 
1641       /* Check for duplicate */
1642       for (c = 0; c < closureSize; c += 2) {
1643         if (closure[c] == cp) break;
1644       }
1645       if (c == closureSize) {
1646         closure[closureSize]   = cp;
1647         closure[closureSize+1] = co;
1648         fifo[fifoSize]         = cp;
1649         fifo[fifoSize+1]       = co;
1650         closureSize           += 2;
1651         fifoSize              += 2;
1652       }
1653     }
1654     fifoStart += 2;
1655   }
1656   if (numPoints) *numPoints = closureSize/2;
1657   if (points)    *points    = closure;
1658   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 #undef __FUNCT__
1663 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1664 /*@C
1665   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1666 
1667   Not collective
1668 
1669   Input Parameters:
1670 + mesh - The DMPlex
1671 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1672 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1673 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1674 
1675   Output Parameters:
1676 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1677 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1678 
1679   Note:
1680   If not using internal storage (points is not NULL on input), this call is unnecessary
1681 
1682   Level: beginner
1683 
1684 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1685 @*/
1686 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1687 {
1688   PetscErrorCode ierr;
1689 
1690   PetscFunctionBegin;
1691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1692   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1693   PetscFunctionReturn(0);
1694 }
1695 
1696 #undef __FUNCT__
1697 #define __FUNCT__ "DMPlexGetFaces"
1698 /*
1699   DMPlexGetFaces -
1700 
1701   Note: This will only work for cell-vertex meshes.
1702 */
1703 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1704 {
1705   DM_Plex        *mesh = (DM_Plex*) dm->data;
1706   const PetscInt *cone = NULL;
1707   PetscInt        depth = 0, dim, coneSize;
1708   PetscErrorCode  ierr;
1709 
1710   PetscFunctionBegin;
1711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1712   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1713   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1714   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1715   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1716   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1717   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1718   switch (dim) {
1719   case 2:
1720     switch (coneSize) {
1721     case 3:
1722       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1723       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1724       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1725       *numFaces         = 3;
1726       *faceSize         = 2;
1727       *faces            = mesh->facesTmp;
1728       break;
1729     case 4:
1730       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1731       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1732       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1733       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1734       *numFaces         = 4;
1735       *faceSize         = 2;
1736       *faces            = mesh->facesTmp;
1737       break;
1738     default:
1739       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1740     }
1741     break;
1742   case 3:
1743     switch (coneSize) {
1744     case 3:
1745       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1746       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1747       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1748       *numFaces         = 3;
1749       *faceSize         = 2;
1750       *faces            = mesh->facesTmp;
1751       break;
1752     case 4:
1753       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1754       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1755       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1756       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1757       *numFaces         = 4;
1758       *faceSize         = 3;
1759       *faces            = mesh->facesTmp;
1760       break;
1761     default:
1762       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1763     }
1764     break;
1765   default:
1766     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1767   }
1768   PetscFunctionReturn(0);
1769 }
1770 
1771 #undef __FUNCT__
1772 #define __FUNCT__ "DMPlexGetMaxSizes"
1773 /*@
1774   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1775 
1776   Not collective
1777 
1778   Input Parameter:
1779 . mesh - The DMPlex
1780 
1781   Output Parameters:
1782 + maxConeSize - The maximum number of in-edges
1783 - maxSupportSize - The maximum number of out-edges
1784 
1785   Level: beginner
1786 
1787 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1788 @*/
1789 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1790 {
1791   DM_Plex *mesh = (DM_Plex*) dm->data;
1792 
1793   PetscFunctionBegin;
1794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1795   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1796   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1797   PetscFunctionReturn(0);
1798 }
1799 
1800 #undef __FUNCT__
1801 #define __FUNCT__ "DMSetUp_Plex"
1802 PetscErrorCode DMSetUp_Plex(DM dm)
1803 {
1804   DM_Plex       *mesh = (DM_Plex*) dm->data;
1805   PetscInt       size;
1806   PetscErrorCode ierr;
1807 
1808   PetscFunctionBegin;
1809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1810   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1811   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1812   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1813   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1814   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1815   if (mesh->maxSupportSize) {
1816     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1817     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1818     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1819   }
1820   PetscFunctionReturn(0);
1821 }
1822 
1823 #undef __FUNCT__
1824 #define __FUNCT__ "DMCreateSubDM_Plex"
1825 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1826 {
1827   PetscSection   section, sectionGlobal;
1828   PetscInt      *subIndices;
1829   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1830   PetscErrorCode ierr;
1831 
1832   PetscFunctionBegin;
1833   if (!numFields) PetscFunctionReturn(0);
1834   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1835   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1836   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1837   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1838   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1839   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1840   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1841   for (p = pStart; p < pEnd; ++p) {
1842     PetscInt gdof;
1843 
1844     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1845     if (gdof > 0) {
1846       for (f = 0; f < numFields; ++f) {
1847         PetscInt fdof, fcdof;
1848 
1849         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1850         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1851         subSize += fdof-fcdof;
1852       }
1853     }
1854   }
1855   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1856   for (p = pStart; p < pEnd; ++p) {
1857     PetscInt gdof, goff;
1858 
1859     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1860     if (gdof > 0) {
1861       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1862       for (f = 0; f < numFields; ++f) {
1863         PetscInt fdof, fcdof, fc, f2, poff = 0;
1864 
1865         /* Can get rid of this loop by storing field information in the global section */
1866         for (f2 = 0; f2 < fields[f]; ++f2) {
1867           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1868           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1869           poff += fdof-fcdof;
1870         }
1871         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1872         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1873         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1874           subIndices[subOff] = goff+poff+fc;
1875         }
1876       }
1877     }
1878   }
1879   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1880   if (subdm) {
1881     PetscSection subsection;
1882     PetscBool    haveNull = PETSC_FALSE;
1883     PetscInt     f, nf = 0;
1884 
1885     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1886     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1887     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1888     for (f = 0; f < numFields; ++f) {
1889       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1890       if ((*subdm)->nullspaceConstructors[f]) {
1891         haveNull = PETSC_TRUE;
1892         nf       = f;
1893       }
1894     }
1895     if (haveNull) {
1896       MatNullSpace nullSpace;
1897 
1898       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1899       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1900       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1901     }
1902     if (dm->fields) {
1903       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1904       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1905       for (f = 0; f < numFields; ++f) {
1906         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1907       }
1908       if (numFields == 1) {
1909         MatNullSpace space;
1910         Mat          pmat;
1911 
1912         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1913         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1914         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1915         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1916         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1917         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1918       }
1919     }
1920   }
1921   PetscFunctionReturn(0);
1922 }
1923 
1924 #undef __FUNCT__
1925 #define __FUNCT__ "DMPlexSymmetrize"
1926 /*@
1927   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1928 
1929   Not collective
1930 
1931   Input Parameter:
1932 . mesh - The DMPlex
1933 
1934   Output Parameter:
1935 
1936   Note:
1937   This should be called after all calls to DMPlexSetCone()
1938 
1939   Level: beginner
1940 
1941 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1942 @*/
1943 PetscErrorCode DMPlexSymmetrize(DM dm)
1944 {
1945   DM_Plex       *mesh = (DM_Plex*) dm->data;
1946   PetscInt      *offsets;
1947   PetscInt       supportSize;
1948   PetscInt       pStart, pEnd, p;
1949   PetscErrorCode ierr;
1950 
1951   PetscFunctionBegin;
1952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1953   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1954   /* Calculate support sizes */
1955   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1956   for (p = pStart; p < pEnd; ++p) {
1957     PetscInt dof, off, c;
1958 
1959     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1960     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1961     for (c = off; c < off+dof; ++c) {
1962       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1963     }
1964   }
1965   for (p = pStart; p < pEnd; ++p) {
1966     PetscInt dof;
1967 
1968     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1969 
1970     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1971   }
1972   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1973   /* Calculate supports */
1974   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1975   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1976   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1977   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1978   for (p = pStart; p < pEnd; ++p) {
1979     PetscInt dof, off, c;
1980 
1981     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1982     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1983     for (c = off; c < off+dof; ++c) {
1984       const PetscInt q = mesh->cones[c];
1985       PetscInt       offS;
1986 
1987       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1988 
1989       mesh->supports[offS+offsets[q]] = p;
1990       ++offsets[q];
1991     }
1992   }
1993   ierr = PetscFree(offsets);CHKERRQ(ierr);
1994   PetscFunctionReturn(0);
1995 }
1996 
1997 #undef __FUNCT__
1998 #define __FUNCT__ "DMPlexSetDepth_Private"
1999 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
2000 {
2001   PetscInt       d;
2002   PetscErrorCode ierr;
2003 
2004   PetscFunctionBegin;
2005   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2006   if (d < 0) {
2007     /* We are guaranteed that the point has a cone since the depth was not yet set */
2008     const PetscInt *cone = NULL;
2009     PetscInt        dCone;
2010 
2011     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2012     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2013     d    = dCone+1;
2014     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2015   }
2016   *depth = d;
2017   PetscFunctionReturn(0);
2018 }
2019 
2020 #undef __FUNCT__
2021 #define __FUNCT__ "DMPlexStratify"
2022 /*@
2023   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2024   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2025   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2026   the DAG.
2027 
2028   Not collective
2029 
2030   Input Parameter:
2031 . mesh - The DMPlex
2032 
2033   Output Parameter:
2034 
2035   Notes:
2036   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2037   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2038 
2039   This should be called after all calls to DMPlexSymmetrize()
2040 
2041   Level: beginner
2042 
2043 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2044 @*/
2045 PetscErrorCode DMPlexStratify(DM dm)
2046 {
2047   DM_Plex       *mesh = (DM_Plex*) dm->data;
2048   PetscInt       pStart, pEnd, p;
2049   PetscInt       numRoots = 0, numLeaves = 0;
2050   PetscErrorCode ierr;
2051 
2052   PetscFunctionBegin;
2053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2054   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2055   /* Calculate depth */
2056   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2057   /* Initialize roots and count leaves */
2058   for (p = pStart; p < pEnd; ++p) {
2059     PetscInt coneSize, supportSize;
2060 
2061     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2062     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2063     if (!coneSize && supportSize) {
2064       ++numRoots;
2065       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2066     } else if (!supportSize && coneSize) {
2067       ++numLeaves;
2068     } else if (!supportSize && !coneSize) {
2069       /* Isolated points */
2070       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2071     }
2072   }
2073   if (numRoots + numLeaves == (pEnd - pStart)) {
2074     for (p = pStart; p < pEnd; ++p) {
2075       PetscInt coneSize, supportSize;
2076 
2077       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2078       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2079       if (!supportSize && coneSize) {
2080         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2081       }
2082     }
2083   } else {
2084     /* This might be slow since lookup is not fast */
2085     for (p = pStart; p < pEnd; ++p) {
2086       PetscInt depth;
2087 
2088       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2089     }
2090   }
2091   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2092   PetscFunctionReturn(0);
2093 }
2094 
2095 #undef __FUNCT__
2096 #define __FUNCT__ "DMPlexGetJoin"
2097 /*@C
2098   DMPlexGetJoin - Get an array for the join of the set of points
2099 
2100   Not Collective
2101 
2102   Input Parameters:
2103 + dm - The DMPlex object
2104 . numPoints - The number of input points for the join
2105 - points - The input points
2106 
2107   Output Parameters:
2108 + numCoveredPoints - The number of points in the join
2109 - coveredPoints - The points in the join
2110 
2111   Level: intermediate
2112 
2113   Note: Currently, this is restricted to a single level join
2114 
2115 .keywords: mesh
2116 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2117 @*/
2118 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2119 {
2120   DM_Plex       *mesh = (DM_Plex*) dm->data;
2121   PetscInt      *join[2];
2122   PetscInt       joinSize, i = 0;
2123   PetscInt       dof, off, p, c, m;
2124   PetscErrorCode ierr;
2125 
2126   PetscFunctionBegin;
2127   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2128   PetscValidPointer(points, 2);
2129   PetscValidPointer(numCoveredPoints, 3);
2130   PetscValidPointer(coveredPoints, 4);
2131   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2132   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2133   /* Copy in support of first point */
2134   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2135   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2136   for (joinSize = 0; joinSize < dof; ++joinSize) {
2137     join[i][joinSize] = mesh->supports[off+joinSize];
2138   }
2139   /* Check each successive support */
2140   for (p = 1; p < numPoints; ++p) {
2141     PetscInt newJoinSize = 0;
2142 
2143     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2144     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2145     for (c = 0; c < dof; ++c) {
2146       const PetscInt point = mesh->supports[off+c];
2147 
2148       for (m = 0; m < joinSize; ++m) {
2149         if (point == join[i][m]) {
2150           join[1-i][newJoinSize++] = point;
2151           break;
2152         }
2153       }
2154     }
2155     joinSize = newJoinSize;
2156     i        = 1-i;
2157   }
2158   *numCoveredPoints = joinSize;
2159   *coveredPoints    = join[i];
2160   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2161   PetscFunctionReturn(0);
2162 }
2163 
2164 #undef __FUNCT__
2165 #define __FUNCT__ "DMPlexRestoreJoin"
2166 /*@C
2167   DMPlexRestoreJoin - Restore an array for the join of the set of points
2168 
2169   Not Collective
2170 
2171   Input Parameters:
2172 + dm - The DMPlex object
2173 . numPoints - The number of input points for the join
2174 - points - The input points
2175 
2176   Output Parameters:
2177 + numCoveredPoints - The number of points in the join
2178 - coveredPoints - The points in the join
2179 
2180   Level: intermediate
2181 
2182 .keywords: mesh
2183 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2184 @*/
2185 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2186 {
2187   PetscErrorCode ierr;
2188 
2189   PetscFunctionBegin;
2190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2191   PetscValidPointer(coveredPoints, 4);
2192   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2193   PetscFunctionReturn(0);
2194 }
2195 
2196 #undef __FUNCT__
2197 #define __FUNCT__ "DMPlexGetFullJoin"
2198 /*@C
2199   DMPlexGetFullJoin - Get an array for the join of the set of points
2200 
2201   Not Collective
2202 
2203   Input Parameters:
2204 + dm - The DMPlex object
2205 . numPoints - The number of input points for the join
2206 - points - The input points
2207 
2208   Output Parameters:
2209 + numCoveredPoints - The number of points in the join
2210 - coveredPoints - The points in the join
2211 
2212   Level: intermediate
2213 
2214 .keywords: mesh
2215 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2216 @*/
2217 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2218 {
2219   DM_Plex       *mesh = (DM_Plex*) dm->data;
2220   PetscInt      *offsets, **closures;
2221   PetscInt      *join[2];
2222   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2223   PetscInt       p, d, c, m;
2224   PetscErrorCode ierr;
2225 
2226   PetscFunctionBegin;
2227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2228   PetscValidPointer(points, 2);
2229   PetscValidPointer(numCoveredPoints, 3);
2230   PetscValidPointer(coveredPoints, 4);
2231 
2232   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2233   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2234   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2235   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2236   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2237   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2238   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2239 
2240   for (p = 0; p < numPoints; ++p) {
2241     PetscInt closureSize;
2242 
2243     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2244 
2245     offsets[p*(depth+2)+0] = 0;
2246     for (d = 0; d < depth+1; ++d) {
2247       PetscInt pStart, pEnd, i;
2248 
2249       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2250       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2251         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2252           offsets[p*(depth+2)+d+1] = i;
2253           break;
2254         }
2255       }
2256       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2257     }
2258     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2259   }
2260   for (d = 0; d < depth+1; ++d) {
2261     PetscInt dof;
2262 
2263     /* Copy in support of first point */
2264     dof = offsets[d+1] - offsets[d];
2265     for (joinSize = 0; joinSize < dof; ++joinSize) {
2266       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2267     }
2268     /* Check each successive cone */
2269     for (p = 1; p < numPoints && joinSize; ++p) {
2270       PetscInt newJoinSize = 0;
2271 
2272       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2273       for (c = 0; c < dof; ++c) {
2274         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2275 
2276         for (m = 0; m < joinSize; ++m) {
2277           if (point == join[i][m]) {
2278             join[1-i][newJoinSize++] = point;
2279             break;
2280           }
2281         }
2282       }
2283       joinSize = newJoinSize;
2284       i        = 1-i;
2285     }
2286     if (joinSize) break;
2287   }
2288   *numCoveredPoints = joinSize;
2289   *coveredPoints    = join[i];
2290   for (p = 0; p < numPoints; ++p) {
2291     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2292   }
2293   ierr = PetscFree(closures);CHKERRQ(ierr);
2294   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2295   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2296   PetscFunctionReturn(0);
2297 }
2298 
2299 #undef __FUNCT__
2300 #define __FUNCT__ "DMPlexGetMeet"
2301 /*@C
2302   DMPlexGetMeet - Get an array for the meet of the set of points
2303 
2304   Not Collective
2305 
2306   Input Parameters:
2307 + dm - The DMPlex object
2308 . numPoints - The number of input points for the meet
2309 - points - The input points
2310 
2311   Output Parameters:
2312 + numCoveredPoints - The number of points in the meet
2313 - coveredPoints - The points in the meet
2314 
2315   Level: intermediate
2316 
2317   Note: Currently, this is restricted to a single level meet
2318 
2319 .keywords: mesh
2320 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2321 @*/
2322 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2323 {
2324   DM_Plex       *mesh = (DM_Plex*) dm->data;
2325   PetscInt      *meet[2];
2326   PetscInt       meetSize, i = 0;
2327   PetscInt       dof, off, p, c, m;
2328   PetscErrorCode ierr;
2329 
2330   PetscFunctionBegin;
2331   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2332   PetscValidPointer(points, 2);
2333   PetscValidPointer(numCoveringPoints, 3);
2334   PetscValidPointer(coveringPoints, 4);
2335   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2336   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2337   /* Copy in cone of first point */
2338   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2339   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2340   for (meetSize = 0; meetSize < dof; ++meetSize) {
2341     meet[i][meetSize] = mesh->cones[off+meetSize];
2342   }
2343   /* Check each successive cone */
2344   for (p = 1; p < numPoints; ++p) {
2345     PetscInt newMeetSize = 0;
2346 
2347     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2348     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2349     for (c = 0; c < dof; ++c) {
2350       const PetscInt point = mesh->cones[off+c];
2351 
2352       for (m = 0; m < meetSize; ++m) {
2353         if (point == meet[i][m]) {
2354           meet[1-i][newMeetSize++] = point;
2355           break;
2356         }
2357       }
2358     }
2359     meetSize = newMeetSize;
2360     i        = 1-i;
2361   }
2362   *numCoveringPoints = meetSize;
2363   *coveringPoints    = meet[i];
2364   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2365   PetscFunctionReturn(0);
2366 }
2367 
2368 #undef __FUNCT__
2369 #define __FUNCT__ "DMPlexRestoreMeet"
2370 /*@C
2371   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2372 
2373   Not Collective
2374 
2375   Input Parameters:
2376 + dm - The DMPlex object
2377 . numPoints - The number of input points for the meet
2378 - points - The input points
2379 
2380   Output Parameters:
2381 + numCoveredPoints - The number of points in the meet
2382 - coveredPoints - The points in the meet
2383 
2384   Level: intermediate
2385 
2386 .keywords: mesh
2387 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2388 @*/
2389 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2390 {
2391   PetscErrorCode ierr;
2392 
2393   PetscFunctionBegin;
2394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2395   PetscValidPointer(coveredPoints, 4);
2396   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2397   PetscFunctionReturn(0);
2398 }
2399 
2400 #undef __FUNCT__
2401 #define __FUNCT__ "DMPlexGetFullMeet"
2402 /*@C
2403   DMPlexGetFullMeet - Get an array for the meet of the set of points
2404 
2405   Not Collective
2406 
2407   Input Parameters:
2408 + dm - The DMPlex object
2409 . numPoints - The number of input points for the meet
2410 - points - The input points
2411 
2412   Output Parameters:
2413 + numCoveredPoints - The number of points in the meet
2414 - coveredPoints - The points in the meet
2415 
2416   Level: intermediate
2417 
2418 .keywords: mesh
2419 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2420 @*/
2421 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2422 {
2423   DM_Plex       *mesh = (DM_Plex*) dm->data;
2424   PetscInt      *offsets, **closures;
2425   PetscInt      *meet[2];
2426   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2427   PetscInt       p, h, c, m;
2428   PetscErrorCode ierr;
2429 
2430   PetscFunctionBegin;
2431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2432   PetscValidPointer(points, 2);
2433   PetscValidPointer(numCoveredPoints, 3);
2434   PetscValidPointer(coveredPoints, 4);
2435 
2436   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2437   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2438   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2439   maxSize = PetscPowInt(mesh->maxConeSize,height);
2440   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2441   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2442 
2443   for (p = 0; p < numPoints; ++p) {
2444     PetscInt closureSize;
2445 
2446     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2447 
2448     offsets[p*(height+2)+0] = 0;
2449     for (h = 0; h < height+1; ++h) {
2450       PetscInt pStart, pEnd, i;
2451 
2452       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2453       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2454         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2455           offsets[p*(height+2)+h+1] = i;
2456           break;
2457         }
2458       }
2459       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2460     }
2461     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2462   }
2463   for (h = 0; h < height+1; ++h) {
2464     PetscInt dof;
2465 
2466     /* Copy in cone of first point */
2467     dof = offsets[h+1] - offsets[h];
2468     for (meetSize = 0; meetSize < dof; ++meetSize) {
2469       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2470     }
2471     /* Check each successive cone */
2472     for (p = 1; p < numPoints && meetSize; ++p) {
2473       PetscInt newMeetSize = 0;
2474 
2475       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2476       for (c = 0; c < dof; ++c) {
2477         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2478 
2479         for (m = 0; m < meetSize; ++m) {
2480           if (point == meet[i][m]) {
2481             meet[1-i][newMeetSize++] = point;
2482             break;
2483           }
2484         }
2485       }
2486       meetSize = newMeetSize;
2487       i        = 1-i;
2488     }
2489     if (meetSize) break;
2490   }
2491   *numCoveredPoints = meetSize;
2492   *coveredPoints    = meet[i];
2493   for (p = 0; p < numPoints; ++p) {
2494     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2495   }
2496   ierr = PetscFree(closures);CHKERRQ(ierr);
2497   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2498   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2499   PetscFunctionReturn(0);
2500 }
2501 
2502 #undef __FUNCT__
2503 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2504 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2505 {
2506   MPI_Comm       comm = ((PetscObject) dm)->comm;
2507   PetscInt       cellDim;
2508   PetscErrorCode ierr;
2509 
2510   PetscFunctionBegin;
2511   PetscValidPointer(numFaceVertices,3);
2512   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2513   switch (cellDim) {
2514   case 0:
2515     *numFaceVertices = 0;
2516     break;
2517   case 1:
2518     *numFaceVertices = 1;
2519     break;
2520   case 2:
2521     switch (numCorners) {
2522     case 3: /* triangle */
2523       *numFaceVertices = 2; /* Edge has 2 vertices */
2524       break;
2525     case 4: /* quadrilateral */
2526       *numFaceVertices = 2; /* Edge has 2 vertices */
2527       break;
2528     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2529       *numFaceVertices = 3; /* Edge has 3 vertices */
2530       break;
2531     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2532       *numFaceVertices = 3; /* Edge has 3 vertices */
2533       break;
2534     default:
2535       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2536     }
2537     break;
2538   case 3:
2539     switch (numCorners) {
2540     case 4: /* tetradehdron */
2541       *numFaceVertices = 3; /* Face has 3 vertices */
2542       break;
2543     case 6: /* tet cohesive cells */
2544       *numFaceVertices = 4; /* Face has 4 vertices */
2545       break;
2546     case 8: /* hexahedron */
2547       *numFaceVertices = 4; /* Face has 4 vertices */
2548       break;
2549     case 9: /* tet cohesive Lagrange cells */
2550       *numFaceVertices = 6; /* Face has 6 vertices */
2551       break;
2552     case 10: /* quadratic tetrahedron */
2553       *numFaceVertices = 6; /* Face has 6 vertices */
2554       break;
2555     case 12: /* hex cohesive Lagrange cells */
2556       *numFaceVertices = 6; /* Face has 6 vertices */
2557       break;
2558     case 18: /* quadratic tet cohesive Lagrange cells */
2559       *numFaceVertices = 6; /* Face has 6 vertices */
2560       break;
2561     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2562       *numFaceVertices = 9; /* Face has 9 vertices */
2563       break;
2564     default:
2565       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2566     }
2567     break;
2568   default:
2569     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2570   }
2571   PetscFunctionReturn(0);
2572 }
2573 
2574 #undef __FUNCT__
2575 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2576 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2577 {
2578   const PetscInt maxFaceCases = 30;
2579   PetscInt       numFaceCases = 0;
2580   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2581   PetscInt      *off, *adj;
2582   PetscInt      *neighborCells, *tmpClosure;
2583   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2584   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2585   PetscErrorCode ierr;
2586 
2587   PetscFunctionBegin;
2588   /* For parallel partitioning, I think you have to communicate supports */
2589   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2590   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2591   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2592   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2593   if (cEnd - cStart == 0) {
2594     if (numVertices) *numVertices = 0;
2595     if (offsets)   *offsets   = NULL;
2596     if (adjacency) *adjacency = NULL;
2597     PetscFunctionReturn(0);
2598   }
2599   numCells = cEnd - cStart;
2600   /* Setup face recognition */
2601   if (depth == 1) {
2602     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 */
2603 
2604     for (c = cStart; c < cEnd; ++c) {
2605       PetscInt corners;
2606 
2607       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2608       if (!cornersSeen[corners]) {
2609         PetscInt nFV;
2610 
2611         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2612         cornersSeen[corners] = 1;
2613 
2614         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2615 
2616         numFaceVertices[numFaceCases++] = nFV;
2617       }
2618     }
2619   }
2620   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2621   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2622   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2623   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2624   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2625   /* Count neighboring cells */
2626   for (cell = cStart; cell < cEnd; ++cell) {
2627     PetscInt numNeighbors = maxNeighbors, n;
2628 
2629     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2630     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2631     for (n = 0; n < numNeighbors; ++n) {
2632       PetscInt        cellPair[2];
2633       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2634       PetscInt        meetSize = 0;
2635       const PetscInt *meet    = NULL;
2636 
2637       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2638       if (cellPair[0] == cellPair[1]) continue;
2639       if (!found) {
2640         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2641         if (meetSize) {
2642           PetscInt f;
2643 
2644           for (f = 0; f < numFaceCases; ++f) {
2645             if (numFaceVertices[f] == meetSize) {
2646               found = PETSC_TRUE;
2647               break;
2648             }
2649           }
2650         }
2651         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2652       }
2653       if (found) ++off[cell-cStart+1];
2654     }
2655   }
2656   /* Prefix sum */
2657   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2658 
2659   if (adjacency) {
2660     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2661     /* Get neighboring cells */
2662     for (cell = cStart; cell < cEnd; ++cell) {
2663       PetscInt numNeighbors = maxNeighbors, n;
2664       PetscInt cellOffset   = 0;
2665 
2666       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2667       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2668       for (n = 0; n < numNeighbors; ++n) {
2669         PetscInt        cellPair[2];
2670         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2671         PetscInt        meetSize = 0;
2672         const PetscInt *meet    = NULL;
2673 
2674         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2675         if (cellPair[0] == cellPair[1]) continue;
2676         if (!found) {
2677           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2678           if (meetSize) {
2679             PetscInt f;
2680 
2681             for (f = 0; f < numFaceCases; ++f) {
2682               if (numFaceVertices[f] == meetSize) {
2683                 found = PETSC_TRUE;
2684                 break;
2685               }
2686             }
2687           }
2688           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2689         }
2690         if (found) {
2691           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2692           ++cellOffset;
2693         }
2694       }
2695     }
2696   }
2697   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2698   if (numVertices) *numVertices = numCells;
2699   if (offsets)   *offsets   = off;
2700   if (adjacency) *adjacency = adj;
2701   PetscFunctionReturn(0);
2702 }
2703 
2704 #if defined(PETSC_HAVE_CHACO)
2705 #if defined(PETSC_HAVE_UNISTD_H)
2706 #include <unistd.h>
2707 #endif
2708 /* Chaco does not have an include file */
2709 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2710                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2711                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2712                        int mesh_dims[3], double *goal, int global_method, int local_method,
2713                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2714 
2715 extern int FREE_GRAPH;
2716 
2717 #undef __FUNCT__
2718 #define __FUNCT__ "DMPlexPartition_Chaco"
2719 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2720 {
2721   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2722   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2723   int            nvtxs          = numVertices; /* number of vertices in full graph */
2724   int           *vwgts          = NULL;   /* weights for all vertices */
2725   float         *ewgts          = NULL;   /* weights for all edges */
2726   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2727   char          *outassignname  = NULL;   /*  name of assignment output file */
2728   char          *outfilename    = NULL;   /* output file name */
2729   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2730   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2731   int            mesh_dims[3];            /* dimensions of mesh of processors */
2732   double        *goal          = NULL;    /* desired set sizes for each set */
2733   int            global_method = 1;       /* global partitioning algorithm */
2734   int            local_method  = 1;       /* local partitioning algorithm */
2735   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2736   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2737   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2738   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2739   long           seed          = 123636512; /* for random graph mutations */
2740   short int     *assignment;              /* Output partition */
2741   int            fd_stdout, fd_pipe[2];
2742   PetscInt      *points;
2743   PetscMPIInt    commSize;
2744   int            i, v, p;
2745   PetscErrorCode ierr;
2746 
2747   PetscFunctionBegin;
2748   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2749   if (!numVertices) {
2750     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2751     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2752     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2753     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2754     PetscFunctionReturn(0);
2755   }
2756   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2757   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2758 
2759   if (global_method == INERTIAL_METHOD) {
2760     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2761     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2762   }
2763   mesh_dims[0] = commSize;
2764   mesh_dims[1] = 1;
2765   mesh_dims[2] = 1;
2766   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2767   /* Chaco outputs to stdout. We redirect this to a buffer. */
2768   /* TODO: check error codes for UNIX calls */
2769 #if defined(PETSC_HAVE_UNISTD_H)
2770   {
2771     int piperet;
2772     piperet = pipe(fd_pipe);
2773     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2774     fd_stdout = dup(1);
2775     close(1);
2776     dup2(fd_pipe[1], 1);
2777   }
2778 #endif
2779   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2780                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2781                    vmax, ndims, eigtol, seed);
2782 #if defined(PETSC_HAVE_UNISTD_H)
2783   {
2784     char msgLog[10000];
2785     int  count;
2786 
2787     fflush(stdout);
2788     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2789     if (count < 0) count = 0;
2790     msgLog[count] = 0;
2791     close(1);
2792     dup2(fd_stdout, 1);
2793     close(fd_stdout);
2794     close(fd_pipe[0]);
2795     close(fd_pipe[1]);
2796     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2797   }
2798 #endif
2799   /* Convert to PetscSection+IS */
2800   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2801   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2802   for (v = 0; v < nvtxs; ++v) {
2803     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2804   }
2805   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2806   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2807   for (p = 0, i = 0; p < commSize; ++p) {
2808     for (v = 0; v < nvtxs; ++v) {
2809       if (assignment[v] == p) points[i++] = v;
2810     }
2811   }
2812   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2813   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2814   if (global_method == INERTIAL_METHOD) {
2815     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2816   }
2817   ierr = PetscFree(assignment);CHKERRQ(ierr);
2818   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2819   PetscFunctionReturn(0);
2820 }
2821 #endif
2822 
2823 #if defined(PETSC_HAVE_PARMETIS)
2824 #undef __FUNCT__
2825 #define __FUNCT__ "DMPlexPartition_ParMetis"
2826 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2827 {
2828   PetscFunctionBegin;
2829   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2830   PetscFunctionReturn(0);
2831 }
2832 #endif
2833 
2834 #undef __FUNCT__
2835 #define __FUNCT__ "DMPlexEnlargePartition"
2836 /* Expand the partition by BFS on the adjacency graph */
2837 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2838 {
2839   PetscHashI      h;
2840   const PetscInt *points;
2841   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2842   PetscInt        pStart, pEnd, part, q;
2843   PetscErrorCode  ierr;
2844 
2845   PetscFunctionBegin;
2846   PetscHashICreate(h);
2847   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2848   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2849   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2850   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2851   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2852   for (part = pStart; part < pEnd; ++part) {
2853     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2854 
2855     PetscHashIClear(h);
2856     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2857     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2858     /* Add all existing points to h */
2859     for (p = 0; p < numPoints; ++p) {
2860       const PetscInt point = points[off+p];
2861       PetscHashIAdd(h, point, 1);
2862     }
2863     PetscHashISize(h, nP);
2864     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2865     /* Add all points in next BFS level */
2866     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2867     for (p = 0; p < numPoints; ++p) {
2868       const PetscInt point = points[off+p];
2869       PetscInt       s     = start[point], e = start[point+1], a;
2870 
2871       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2872     }
2873     PetscHashISize(h, numNewPoints);
2874     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2875     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2876     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2877     totPoints += numNewPoints;
2878   }
2879   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2880   PetscHashIDestroy(h);
2881   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2882   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2883   for (part = pStart, q = 0; part < pEnd; ++part) {
2884     PetscInt numPoints, p;
2885 
2886     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2887     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2888     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2889   }
2890   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2891   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2892   PetscFunctionReturn(0);
2893 }
2894 
2895 #undef __FUNCT__
2896 #define __FUNCT__ "DMPlexCreatePartition"
2897 /*
2898   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2899 
2900   Collective on DM
2901 
2902   Input Parameters:
2903   + dm - The DM
2904   . height - The height for points in the partition
2905   - enlarge - Expand each partition with neighbors
2906 
2907   Output Parameters:
2908   + partSection - The PetscSection giving the division of points by partition
2909   . partition - The list of points by partition
2910   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2911   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2912 
2913   Level: developer
2914 
2915 .seealso DMPlexDistribute()
2916 */
2917 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2918 {
2919   PetscMPIInt    size;
2920   PetscErrorCode ierr;
2921 
2922   PetscFunctionBegin;
2923   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2924 
2925   *origPartSection = NULL;
2926   *origPartition   = NULL;
2927   if (size == 1) {
2928     PetscInt *points;
2929     PetscInt  cStart, cEnd, c;
2930 
2931     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2932     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2933     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2934     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2935     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2936     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2937     for (c = cStart; c < cEnd; ++c) points[c] = c;
2938     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2939     PetscFunctionReturn(0);
2940   }
2941   if (height == 0) {
2942     PetscInt  numVertices;
2943     PetscInt *start     = NULL;
2944     PetscInt *adjacency = NULL;
2945 
2946     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2947     if (1) {
2948 #if defined(PETSC_HAVE_CHACO)
2949       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2950 #endif
2951     } else {
2952 #if defined(PETSC_HAVE_PARMETIS)
2953       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2954 #endif
2955     }
2956     if (enlarge) {
2957       *origPartSection = *partSection;
2958       *origPartition   = *partition;
2959 
2960       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2961     }
2962     ierr = PetscFree(start);CHKERRQ(ierr);
2963     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2964 # if 0
2965   } else if (height == 1) {
2966     /* Build the dual graph for faces and partition the hypergraph */
2967     PetscInt numEdges;
2968 
2969     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2970     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2971     destroyCSR(numEdges, start, adjacency);
2972 #endif
2973   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2974   PetscFunctionReturn(0);
2975 }
2976 
2977 #undef __FUNCT__
2978 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2979 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2980 {
2981   /* const PetscInt  height = 0; */
2982   const PetscInt *partArray;
2983   PetscInt       *allPoints, *partPoints = NULL;
2984   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2985   PetscErrorCode  ierr;
2986 
2987   PetscFunctionBegin;
2988   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2989   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2990   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2991   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2992   for (rank = rStart; rank < rEnd; ++rank) {
2993     PetscInt partSize = 0;
2994     PetscInt numPoints, offset, p;
2995 
2996     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2997     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2998     for (p = 0; p < numPoints; ++p) {
2999       PetscInt  point   = partArray[offset+p], closureSize, c;
3000       PetscInt *closure = NULL;
3001 
3002       /* TODO Include support for height > 0 case */
3003       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3004       /* Merge into existing points */
3005       if (partSize+closureSize > maxPartSize) {
3006         PetscInt *tmpPoints;
3007 
3008         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3009         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3010         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3011         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3012 
3013         partPoints = tmpPoints;
3014       }
3015       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3016       partSize += closureSize;
3017 
3018       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3019       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3020     }
3021     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3022   }
3023   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3024   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3025   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3026 
3027   for (rank = rStart; rank < rEnd; ++rank) {
3028     PetscInt partSize = 0, newOffset;
3029     PetscInt numPoints, offset, p;
3030 
3031     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3032     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3033     for (p = 0; p < numPoints; ++p) {
3034       PetscInt  point   = partArray[offset+p], closureSize, c;
3035       PetscInt *closure = NULL;
3036 
3037       /* TODO Include support for height > 0 case */
3038       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3039       /* Merge into existing points */
3040       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3041       partSize += closureSize;
3042 
3043       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3044       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3045     }
3046     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3047     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3048   }
3049   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3050   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3051   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3052   PetscFunctionReturn(0);
3053 }
3054 
3055 #undef __FUNCT__
3056 #define __FUNCT__ "DMPlexDistributeField"
3057 /*
3058   Input Parameters:
3059 . originalSection
3060 , originalVec
3061 
3062   Output Parameters:
3063 . newSection
3064 . newVec
3065 */
3066 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3067 {
3068   PetscSF        fieldSF;
3069   PetscInt      *remoteOffsets, fieldSize;
3070   PetscScalar   *originalValues, *newValues;
3071   PetscErrorCode ierr;
3072 
3073   PetscFunctionBegin;
3074   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3075 
3076   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3077   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3078   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3079 
3080   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3081   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3082   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3083   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3084   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3085   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3086   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3087   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3088   PetscFunctionReturn(0);
3089 }
3090 
3091 #undef __FUNCT__
3092 #define __FUNCT__ "DMPlexDistribute"
3093 /*@C
3094   DMPlexDistribute - Distributes the mesh and any associated sections.
3095 
3096   Not Collective
3097 
3098   Input Parameter:
3099 + dm  - The original DMPlex object
3100 . partitioner - The partitioning package, or NULL for the default
3101 - overlap - The overlap of partitions, 0 is the default
3102 
3103   Output Parameter:
3104 . parallelMesh - The distributed DMPlex object, or NULL
3105 
3106   Note: If the mesh was not distributed, the return value is NULL
3107 
3108   Level: intermediate
3109 
3110 .keywords: mesh, elements
3111 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3112 @*/
3113 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3114 {
3115   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3116   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3117   const PetscInt         height = 0;
3118   PetscInt               dim, numRemoteRanks;
3119   IS                     origCellPart,        cellPart,        part;
3120   PetscSection           origCellPartSection, cellPartSection, partSection;
3121   PetscSFNode           *remoteRanks;
3122   PetscSF                partSF, pointSF, coneSF;
3123   ISLocalToGlobalMapping renumbering;
3124   PetscSection           originalConeSection, newConeSection;
3125   PetscInt              *remoteOffsets;
3126   PetscInt              *cones, *newCones, newConesSize;
3127   PetscBool              flg;
3128   PetscMPIInt            rank, numProcs, p;
3129   PetscErrorCode         ierr;
3130 
3131   PetscFunctionBegin;
3132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3133   PetscValidPointer(dmParallel,4);
3134 
3135   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3136   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3137   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3138 
3139   *dmParallel = NULL;
3140   if (numProcs == 1) PetscFunctionReturn(0);
3141 
3142   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3143   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3144   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3145   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3146   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3147   if (!rank) numRemoteRanks = numProcs;
3148   else       numRemoteRanks = 0;
3149   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3150   for (p = 0; p < numRemoteRanks; ++p) {
3151     remoteRanks[p].rank  = p;
3152     remoteRanks[p].index = 0;
3153   }
3154   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3155   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3156   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3157   if (flg) {
3158     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3159     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3160     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3161     if (origCellPart) {
3162       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3163       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3164       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3165     }
3166     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3167   }
3168   /* Close the partition over the mesh */
3169   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3170   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3171   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3172   /* Create new mesh */
3173   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3174   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3175   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3176   pmesh = (DM_Plex*) (*dmParallel)->data;
3177   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3178   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3179   if (flg) {
3180     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3181     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3182     ierr = ISView(part, NULL);CHKERRQ(ierr);
3183     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3184     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3185     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3186   }
3187   /* Distribute cone section */
3188   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3189   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3190   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3191   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3192   {
3193     PetscInt pStart, pEnd, p;
3194 
3195     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3196     for (p = pStart; p < pEnd; ++p) {
3197       PetscInt coneSize;
3198       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3199       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3200     }
3201   }
3202   /* Communicate and renumber cones */
3203   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3204   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3205   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3206   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3209   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3210   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3211   if (flg) {
3212     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3213     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3214     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3215     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3216     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3217   }
3218   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3219   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3220   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3221   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3222   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3223   /* Create supports and stratify sieve */
3224   {
3225     PetscInt pStart, pEnd;
3226 
3227     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3228     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3229   }
3230   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3231   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3232   /* Distribute Coordinates */
3233   {
3234     PetscSection originalCoordSection, newCoordSection;
3235     Vec          originalCoordinates, newCoordinates;
3236     const char  *name;
3237 
3238     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3239     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3240     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3241     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3242     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3243     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3244 
3245     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3246     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3247     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3248   }
3249   /* Distribute labels */
3250   {
3251     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3252     PetscInt numLabels = 0, l;
3253 
3254     /* Bcast number of labels */
3255     while (next) {
3256       ++numLabels; next = next->next;
3257     }
3258     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259     next = mesh->labels;
3260     for (l = 0; l < numLabels; ++l) {
3261       DMLabel         newLabel;
3262       const PetscInt *partArray;
3263       char           *name;
3264       PetscInt       *stratumSizes = NULL, *points = NULL;
3265       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3266       PetscInt        nameSize, s, p;
3267       PetscBool       isdepth;
3268       size_t          len = 0;
3269 
3270       /* Bcast name (could filter for no points) */
3271       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3272       nameSize = len;
3273       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3274       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3275       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3276       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3277       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3278       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3279       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3280       newLabel->name = name;
3281       /* Bcast numStrata (could filter for no points in stratum) */
3282       if (!rank) newLabel->numStrata = next->numStrata;
3283       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3284       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3285                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3286                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3287       /* Bcast stratumValues (could filter for no points in stratum) */
3288       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3289       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3290       /* Find size on each process and Scatter */
3291       if (!rank) {
3292         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3293         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3294         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));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                   ++stratumSizes[proc*next->numStrata+s];
3308                   break;
3309                 }
3310               }
3311             }
3312           }
3313         }
3314         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3315       }
3316       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3317       /* Calculate stratumOffsets */
3318       newLabel->stratumOffsets[0] = 0;
3319       for (s = 0; s < newLabel->numStrata; ++s) {
3320         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3321       }
3322       /* Pack points and Scatter */
3323       if (!rank) {
3324         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3325         displs[0] = 0;
3326         for (p = 0; p < numProcs; ++p) {
3327           sendcnts[p] = 0;
3328           for (s = 0; s < next->numStrata; ++s) {
3329             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3330           }
3331           offsets[p]  = displs[p];
3332           displs[p+1] = displs[p] + sendcnts[p];
3333         }
3334         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3335         for (s = 0; s < next->numStrata; ++s) {
3336           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3337             const PetscInt point = next->points[p];
3338             PetscInt       proc;
3339 
3340             for (proc = 0; proc < numProcs; ++proc) {
3341               PetscInt dof, off, pPart;
3342 
3343               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3344               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3345               for (pPart = off; pPart < off+dof; ++pPart) {
3346                 if (partArray[pPart] == point) {
3347                   points[offsets[proc]++] = point;
3348                   break;
3349                 }
3350               }
3351             }
3352           }
3353         }
3354       }
3355       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3356       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3357       ierr = PetscFree(points);CHKERRQ(ierr);
3358       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3359       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3360       /* Renumber points */
3361       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3362       /* Sort points */
3363       for (s = 0; s < newLabel->numStrata; ++s) {
3364         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3365       }
3366       /* Insert into list */
3367       if (newNext) newNext->next = newLabel;
3368       else pmesh->labels = newLabel;
3369       newNext = newLabel;
3370       if (!rank) next = next->next;
3371     }
3372   }
3373   /* Cleanup Partition */
3374   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3375   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3376   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3377   ierr = ISDestroy(&part);CHKERRQ(ierr);
3378   /* Create point SF for parallel mesh */
3379   {
3380     const PetscInt *leaves;
3381     PetscSFNode    *remotePoints, *rowners, *lowners;
3382     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3383     PetscInt        pStart, pEnd;
3384 
3385     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3386     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3387     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3388     for (p=0; p<numRoots; p++) {
3389       rowners[p].rank  = -1;
3390       rowners[p].index = -1;
3391     }
3392     if (origCellPart) {
3393       /* Make sure cells in the original partition are not assigned to other procs */
3394       const PetscInt *origCells;
3395 
3396       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3397       for (p = 0; p < numProcs; ++p) {
3398         PetscInt dof, off, d;
3399 
3400         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3401         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3402         for (d = off; d < off+dof; ++d) {
3403           rowners[origCells[d]].rank = p;
3404         }
3405       }
3406       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3407     }
3408     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3409     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3410 
3411     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3412     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3413     for (p = 0; p < numLeaves; ++p) {
3414       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3415         lowners[p].rank  = rank;
3416         lowners[p].index = leaves ? leaves[p] : p;
3417       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3418         lowners[p].rank  = -2;
3419         lowners[p].index = -2;
3420       }
3421     }
3422     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3423       rowners[p].rank  = -3;
3424       rowners[p].index = -3;
3425     }
3426     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3427     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3428     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3429     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3430     for (p = 0; p < numLeaves; ++p) {
3431       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3432       if (lowners[p].rank != rank) ++numGhostPoints;
3433     }
3434     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3435     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3436     for (p = 0, gp = 0; p < numLeaves; ++p) {
3437       if (lowners[p].rank != rank) {
3438         ghostPoints[gp]        = leaves ? leaves[p] : p;
3439         remotePoints[gp].rank  = lowners[p].rank;
3440         remotePoints[gp].index = lowners[p].index;
3441         ++gp;
3442       }
3443     }
3444     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3445     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3446     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3447   }
3448   /* Cleanup */
3449   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3450   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3451   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3452   PetscFunctionReturn(0);
3453 }
3454 
3455 #undef __FUNCT__
3456 #define __FUNCT__ "DMPlexRenumber_Private"
3457 /*
3458   Reasons to renumber:
3459 
3460   1) Permute points, e.g. bandwidth reduction (Renumber)
3461 
3462     a) Must not mix strata
3463 
3464   2) Shift numbers for point insertion (Shift)
3465 
3466     a) Want operation brken into parts so that insertion can be interleaved
3467 
3468   renumbering - An IS which provides the new numbering
3469 */
3470 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3471 {
3472   PetscFunctionBegin;
3473   PetscFunctionReturn(0);
3474 }
3475 
3476 #undef __FUNCT__
3477 #define __FUNCT__ "DMPlexShiftPoint_Private"
3478 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3479 {
3480   if (depth < 0) return p;
3481   /* Cells    */ if (p < depthEnd[depth])   return p;
3482   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3483   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3484   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3485 }
3486 
3487 #undef __FUNCT__
3488 #define __FUNCT__ "DMPlexShiftSizes_Private"
3489 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3490 {
3491   PetscInt      *depthEnd;
3492   PetscInt       depth = 0, d, pStart, pEnd, p;
3493   PetscErrorCode ierr;
3494 
3495   PetscFunctionBegin;
3496   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3497   if (depth < 0) PetscFunctionReturn(0);
3498   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3499   /* Step 1: Expand chart */
3500   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3501   for (d = 0; d <= depth; ++d) {
3502     pEnd += depthShift[d];
3503     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3504   }
3505   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3506   /* Step 2: Set cone and support sizes */
3507   for (d = 0; d <= depth; ++d) {
3508     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3509     for (p = pStart; p < pEnd; ++p) {
3510       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3511       PetscInt size;
3512 
3513       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3514       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3515       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3516       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3517     }
3518   }
3519   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3520   PetscFunctionReturn(0);
3521 }
3522 
3523 #undef __FUNCT__
3524 #define __FUNCT__ "DMPlexShiftPoints_Private"
3525 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3526 {
3527   PetscInt      *depthEnd, *newpoints;
3528   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3529   PetscErrorCode ierr;
3530 
3531   PetscFunctionBegin;
3532   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3533   if (depth < 0) PetscFunctionReturn(0);
3534   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3535   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3536   for (d = 0; d <= depth; ++d) {
3537     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3538   }
3539   /* Step 5: Set cones and supports */
3540   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3541   for (p = pStart; p < pEnd; ++p) {
3542     const PetscInt *points = NULL, *orientations = NULL;
3543     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3544 
3545     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3546     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3547     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3548     for (i = 0; i < size; ++i) {
3549       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3550     }
3551     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3552     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3553     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3554     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3555     for (i = 0; i < size; ++i) {
3556       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3557     }
3558     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3559   }
3560   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3561   PetscFunctionReturn(0);
3562 }
3563 
3564 #undef __FUNCT__
3565 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3566 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3567 {
3568   PetscSection   coordSection, newCoordSection;
3569   Vec            coordinates, newCoordinates;
3570   PetscScalar   *coords, *newCoords;
3571   PetscInt      *depthEnd, coordSize;
3572   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3573   PetscErrorCode ierr;
3574 
3575   PetscFunctionBegin;
3576   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3577   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3578   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3579   for (d = 0; d <= depth; ++d) {
3580     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3581   }
3582   /* Step 8: Convert coordinates */
3583   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3584   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3585   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3586   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3587   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3588   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3589   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3590   for (v = vStartNew; v < vEndNew; ++v) {
3591     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3592     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3593   }
3594   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3595   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3596   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3597   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3598   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3599   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3600   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3601   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3602   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3603   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3604   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3605   for (v = vStart; v < vEnd; ++v) {
3606     PetscInt dof, off, noff, d;
3607 
3608     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3609     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3610     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3611     for (d = 0; d < dof; ++d) {
3612       newCoords[noff+d] = coords[off+d];
3613     }
3614   }
3615   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3616   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3617   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3618   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3619   PetscFunctionReturn(0);
3620 }
3621 
3622 #undef __FUNCT__
3623 #define __FUNCT__ "DMPlexShiftSF_Private"
3624 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3625 {
3626   PetscInt          *depthEnd;
3627   PetscInt           depth = 0, d;
3628   PetscSF            sfPoint, sfPointNew;
3629   const PetscSFNode *remotePoints;
3630   PetscSFNode       *gremotePoints;
3631   const PetscInt    *localPoints;
3632   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3633   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3634   PetscMPIInt        numProcs;
3635   PetscErrorCode     ierr;
3636 
3637   PetscFunctionBegin;
3638   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3639   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3640   for (d = 0; d <= depth; ++d) {
3641     totShift += depthShift[d];
3642     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3643   }
3644   /* Step 9: Convert pointSF */
3645   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3646   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3647   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3648   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3649   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3650   if (numRoots >= 0) {
3651     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3652     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3653     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3654     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3655     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3656     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3657     for (l = 0; l < numLeaves; ++l) {
3658       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3659       gremotePoints[l].rank  = remotePoints[l].rank;
3660       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3661     }
3662     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3663     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3664   }
3665   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3666   PetscFunctionReturn(0);
3667 }
3668 
3669 #undef __FUNCT__
3670 #define __FUNCT__ "DMPlexShiftLabels_Private"
3671 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3672 {
3673   PetscSF            sfPoint;
3674   DMLabel            vtkLabel, ghostLabel;
3675   PetscInt          *depthEnd;
3676   const PetscSFNode *leafRemote;
3677   const PetscInt    *leafLocal;
3678   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3679   PetscMPIInt        rank;
3680   PetscErrorCode     ierr;
3681 
3682   PetscFunctionBegin;
3683   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3684   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3685   for (d = 0; d <= depth; ++d) {
3686     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3687   }
3688   /* Step 10: Convert labels */
3689   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3690   for (l = 0; l < numLabels; ++l) {
3691     DMLabel         label, newlabel;
3692     const char     *lname;
3693     PetscBool       isDepth;
3694     IS              valueIS;
3695     const PetscInt *values;
3696     PetscInt        numValues, val;
3697 
3698     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3699     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3700     if (isDepth) continue;
3701     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3702     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3703     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3704     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3705     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3706     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3707     for (val = 0; val < numValues; ++val) {
3708       IS              pointIS;
3709       const PetscInt *points;
3710       PetscInt        numPoints, p;
3711 
3712       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3713       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3714       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3715       for (p = 0; p < numPoints; ++p) {
3716         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3717 
3718         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3719       }
3720       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3721       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3722     }
3723     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3724     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3725   }
3726   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3727   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3728   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3729   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3730   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3731   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3732   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3733   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3734   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3735   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3736   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3737     for (; c < leafLocal[l] && c < cEnd; ++c) {
3738       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3739     }
3740     if (leafLocal[l] >= cEnd) break;
3741     if (leafRemote[l].rank == rank) {
3742       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3743     } else {
3744       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3745     }
3746   }
3747   for (; c < cEnd; ++c) {
3748     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3749   }
3750   if (0) {
3751     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3752     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3753     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3754   }
3755   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3756   for (f = fStart; f < fEnd; ++f) {
3757     PetscInt numCells;
3758 
3759     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3760     if (numCells < 2) {
3761       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3762     } else {
3763       const PetscInt *cells = NULL;
3764       PetscInt        vA, vB;
3765 
3766       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3767       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3768       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3769       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3770     }
3771   }
3772   if (0) {
3773     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3774     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3775     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3776   }
3777   PetscFunctionReturn(0);
3778 }
3779 
3780 #undef __FUNCT__
3781 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3782 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3783 {
3784   DMLabel         label;
3785   IS              valueIS;
3786   const PetscInt *values;
3787   PetscInt       *depthShift;
3788   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3789   PetscErrorCode  ierr;
3790 
3791   PetscFunctionBegin;
3792   /* Count ghost cells */
3793   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3794   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3795   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3796   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3797 
3798   *numGhostCells = 0;
3799   for (fs = 0; fs < numFS; ++fs) {
3800     PetscInt numBdFaces;
3801 
3802     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3803 
3804     *numGhostCells += numBdFaces;
3805   }
3806   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3807   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3808   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3809   if (depth >= 0) depthShift[depth] = *numGhostCells;
3810   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3811   /* Step 3: Set cone/support sizes for new points */
3812   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3813   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3814     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3815   }
3816   for (fs = 0; fs < numFS; ++fs) {
3817     IS              faceIS;
3818     const PetscInt *faces;
3819     PetscInt        numFaces, f;
3820 
3821     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3822     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3823     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3824     for (f = 0; f < numFaces; ++f) {
3825       PetscInt size;
3826 
3827       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3828       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3829       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3830     }
3831     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3832     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3833   }
3834   /* Step 4: Setup ghosted DM */
3835   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3836   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3837   /* Step 6: Set cones and supports for new points */
3838   ghostCell = cEnd;
3839   for (fs = 0; fs < numFS; ++fs) {
3840     IS              faceIS;
3841     const PetscInt *faces;
3842     PetscInt        numFaces, f;
3843 
3844     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3845     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3846     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3847     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3848       PetscInt newFace = faces[f] + *numGhostCells;
3849 
3850       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3851       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3852     }
3853     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3854     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3855   }
3856   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3857   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3858   /* Step 7: Stratify */
3859   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3860   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3861   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3862   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3863   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3864   PetscFunctionReturn(0);
3865 }
3866 
3867 #undef __FUNCT__
3868 #define __FUNCT__ "DMPlexConstructGhostCells"
3869 /*@C
3870   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3871 
3872   Collective on dm
3873 
3874   Input Parameters:
3875 + dm - The original DM
3876 - labelName - The label specifying the boundary faces (this could be auto-generated)
3877 
3878   Output Parameters:
3879 + numGhostCells - The number of ghost cells added to the DM
3880 - dmGhosted - The new DM
3881 
3882   Level: developer
3883 
3884 .seealso: DMCreate()
3885 */
3886 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3887 {
3888   DM             gdm;
3889   PetscInt       dim;
3890   PetscErrorCode ierr;
3891 
3892   PetscFunctionBegin;
3893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3894   PetscValidPointer(numGhostCells, 3);
3895   PetscValidPointer(dmGhosted, 4);
3896   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3897   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3898   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3899   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3900   switch (dim) {
3901   case 2:
3902     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3903     break;
3904   default:
3905     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3906   }
3907   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3908   *dmGhosted = gdm;
3909   PetscFunctionReturn(0);
3910 }
3911 
3912 #undef __FUNCT__
3913 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3914 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3915 {
3916   MPI_Comm        comm = ((PetscObject) dm)->comm;
3917   IS              valueIS, *pointIS;
3918   const PetscInt *values, **splitPoints;
3919   PetscSection    coordSection;
3920   Vec             coordinates;
3921   PetscScalar    *coords;
3922   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3923   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3924   PetscErrorCode  ierr;
3925 
3926   PetscFunctionBegin;
3927   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3928   /* Count split points and add cohesive cells */
3929   if (label) {
3930     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3931     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3932     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3933   }
3934   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3935   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3936   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3937   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3938   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3939   for (d = 0; d <= depth; ++d) {
3940     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3941     numSplitPoints[d] = 0;
3942     splitPoints[d]    = NULL;
3943     pointIS[d]        = NULL;
3944   }
3945   for (sp = 0; sp < numSP; ++sp) {
3946     const PetscInt dep = values[sp];
3947 
3948     if ((dep < 0) || (dep > depth)) continue;
3949     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3950     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3951     if (pointIS[dep]) {
3952       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3953       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3954     }
3955   }
3956   if (depth >= 0) {
3957     /* Calculate number of additional points */
3958     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3959     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3960     /* Calculate hybrid bound for each dimension */
3961     pMaxNew[0] += depthShift[depth];
3962     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3963     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3964 
3965     /* Calculate point offset for each dimension */
3966     depthOffset[depth] = 0;
3967     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3968     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3969     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3970   }
3971   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3972   /* Step 3: Set cone/support sizes for new points */
3973   for (dep = 0; dep <= depth; ++dep) {
3974     for (p = 0; p < numSplitPoints[dep]; ++p) {
3975       const PetscInt  oldp   = splitPoints[dep][p];
3976       const PetscInt  newp   = depthOffset[dep] + oldp;
3977       const PetscInt  splitp = pMaxNew[dep] + p;
3978       const PetscInt *support;
3979       PetscInt        coneSize, supportSize, q, e;
3980 
3981       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3982       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3983       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3984       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3985       if (dep == depth-1) {
3986         const PetscInt ccell = pMaxNew[depth] + p;
3987         /* Add cohesive cells, they are prisms */
3988         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3989       } else if (dep == 0) {
3990         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3991 
3992         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3993         /* Split old vertex: Edges in old split faces and new cohesive edge */
3994         for (e = 0, q = 0; e < supportSize; ++e) {
3995           PetscInt val;
3996 
3997           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3998           if ((val == 1) || (val == (shift + 1))) ++q;
3999         }
4000         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4001         /* Split new vertex: Edges in new split faces and new cohesive edge */
4002         for (e = 0, q = 0; e < supportSize; ++e) {
4003           PetscInt val;
4004 
4005           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4006           if ((val == 1) || (val == -(shift + 1))) ++q;
4007         }
4008         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4009         /* Add cohesive edges */
4010         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4011         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4012       } else if (dep == dim-2) {
4013         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4014         /* Split old edge: Faces in positive side cells and old split faces */
4015         for (e = 0, q = 0; e < supportSize; ++e) {
4016           PetscInt val;
4017 
4018           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4019           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4020         }
4021         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4022         /* Split new edge: Faces in negative side cells and new split faces */
4023         for (e = 0, q = 0; e < supportSize; ++e) {
4024           PetscInt val;
4025 
4026           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4027           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4028         }
4029         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4030       }
4031     }
4032   }
4033   /* Step 4: Setup split DM */
4034   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4035   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4036   /* Step 6: Set cones and supports for new points */
4037   for (dep = 0; dep <= depth; ++dep) {
4038     for (p = 0; p < numSplitPoints[dep]; ++p) {
4039       const PetscInt  oldp   = splitPoints[dep][p];
4040       const PetscInt  newp   = depthOffset[dep] + oldp;
4041       const PetscInt  splitp = pMaxNew[dep] + p;
4042       const PetscInt *cone, *support, *ornt;
4043       PetscInt        coneSize, supportSize, q, v, e, s;
4044 
4045       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4046       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4047       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4048       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4049       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4050       if (dep == depth-1) {
4051         const PetscInt  ccell = pMaxNew[depth] + p;
4052         const PetscInt *supportF;
4053 
4054         /* Split face:       copy in old face to new face to start */
4055         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4056         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4057         /* Split old face:   old vertices/edges in cone so no change */
4058         /* Split new face:   new vertices/edges in cone */
4059         for (q = 0; q < coneSize; ++q) {
4060           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4061 
4062           coneNew[2+q] = pMaxNew[dim-2] + v;
4063         }
4064         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4065         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4066         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4067         coneNew[0] = newp;
4068         coneNew[1] = splitp;
4069         for (q = 0; q < coneSize; ++q) {
4070           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4071         }
4072         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4073 
4074 
4075         for (s = 0; s < supportSize; ++s) {
4076           PetscInt val;
4077 
4078           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4079           if (val < 0) {
4080             /* Split old face:   Replace negative side cell with cohesive cell */
4081             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4082           } else {
4083             /* Split new face:   Replace positive side cell with cohesive cell */
4084             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4085           }
4086         }
4087       } else if (dep == 0) {
4088         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4089 
4090         /* Split old vertex: Edges in old split faces and new cohesive edge */
4091         for (e = 0, q = 0; e < supportSize; ++e) {
4092           PetscInt val;
4093 
4094           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4095           if ((val == 1) || (val == (shift + 1))) {
4096             supportNew[q++] = depthOffset[1] + support[e];
4097           }
4098         }
4099         supportNew[q] = cedge;
4100 
4101         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4102         /* Split new vertex: Edges in new split faces and new cohesive edge */
4103         for (e = 0, q = 0; e < supportSize; ++e) {
4104           PetscInt val, edge;
4105 
4106           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4107           if (val == 1) {
4108             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4109             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4110             supportNew[q++] = pMaxNew[1] + edge;
4111           } else if (val == -(shift + 1)) {
4112             supportNew[q++] = depthOffset[1] + support[e];
4113           }
4114         }
4115         supportNew[q] = cedge;
4116         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4117         /* Cohesive edge:    Old and new split vertex, punting on support */
4118         coneNew[0] = newp;
4119         coneNew[1] = splitp;
4120         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4121       } else if (dep == dim-2) {
4122         /* Split old edge:   old vertices in cone so no change */
4123         /* Split new edge:   new vertices in cone */
4124         for (q = 0; q < coneSize; ++q) {
4125           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4126 
4127           coneNew[q] = pMaxNew[dim-3] + v;
4128         }
4129         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4130         /* Split old edge: Faces in positive side cells and old split faces */
4131         for (e = 0, q = 0; e < supportSize; ++e) {
4132           PetscInt val;
4133 
4134           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4135           if ((val == dim-1) || (val == (shift + dim-1))) {
4136             supportNew[q++] = depthOffset[dim-1] + support[e];
4137           }
4138         }
4139         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4140         /* Split new edge: Faces in negative side cells and new split faces */
4141         for (e = 0, q = 0; e < supportSize; ++e) {
4142           PetscInt val, face;
4143 
4144           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4145           if (val == dim-1) {
4146             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4147             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4148             supportNew[q++] = pMaxNew[dim-1] + face;
4149           } else if (val == -(shift + dim-1)) {
4150             supportNew[q++] = depthOffset[dim-1] + support[e];
4151           }
4152         }
4153         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4154       }
4155     }
4156   }
4157   /* Step 6b: Replace split points in negative side cones */
4158   for (sp = 0; sp < numSP; ++sp) {
4159     PetscInt        dep = values[sp];
4160     IS              pIS;
4161     PetscInt        numPoints;
4162     const PetscInt *points;
4163 
4164     if (dep >= 0) continue;
4165     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4166     if (!pIS) continue;
4167     dep  = -dep - shift;
4168     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4169     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4170     for (p = 0; p < numPoints; ++p) {
4171       const PetscInt  oldp = points[p];
4172       const PetscInt  newp = depthOffset[dep] + oldp;
4173       const PetscInt *cone;
4174       PetscInt        coneSize, c;
4175       PetscBool       replaced = PETSC_FALSE;
4176 
4177       /* Negative edge: replace split vertex */
4178       /* Negative cell: replace split face */
4179       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4180       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4181       for (c = 0; c < coneSize; ++c) {
4182         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4183         PetscInt       csplitp, cp, val;
4184 
4185         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4186         if (val == dep-1) {
4187           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4188           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4189           csplitp  = pMaxNew[dep-1] + cp;
4190           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4191           replaced = PETSC_TRUE;
4192         }
4193       }
4194       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4195     }
4196     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4197     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4198   }
4199   /* Step 7: Stratify */
4200   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4201   /* Step 8: Coordinates */
4202   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4203   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4204   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4205   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4206   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4207     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4208     const PetscInt splitp = pMaxNew[0] + v;
4209     PetscInt       dof, off, soff, d;
4210 
4211     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4212     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4213     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4214     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4215   }
4216   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4217   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4218   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4219   /* Step 10: Labels */
4220   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4221   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4222   for (dep = 0; dep <= depth; ++dep) {
4223     for (p = 0; p < numSplitPoints[dep]; ++p) {
4224       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4225       const PetscInt splitp = pMaxNew[dep] + p;
4226       PetscInt       l;
4227 
4228       for (l = 0; l < numLabels; ++l) {
4229         DMLabel     mlabel;
4230         const char *lname;
4231         PetscInt    val;
4232 
4233         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4234         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4235         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4236         if (val >= 0) {
4237           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4238           if (dep == 0) {
4239             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4240             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4241           }
4242         }
4243       }
4244     }
4245   }
4246   for (sp = 0; sp < numSP; ++sp) {
4247     const PetscInt dep = values[sp];
4248 
4249     if ((dep < 0) || (dep > depth)) continue;
4250     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4251     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4252   }
4253   if (label) {
4254     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4255     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4256   }
4257   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4258   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4259   PetscFunctionReturn(0);
4260 }
4261 
4262 #undef __FUNCT__
4263 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4264 /*@C
4265   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4266 
4267   Collective on dm
4268 
4269   Input Parameters:
4270 + dm - The original DM
4271 - labelName - The label specifying the boundary faces (this could be auto-generated)
4272 
4273   Output Parameters:
4274 - dmSplit - The new DM
4275 
4276   Level: developer
4277 
4278 .seealso: DMCreate()
4279 */
4280 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4281 {
4282   DM             sdm;
4283   PetscInt       dim;
4284   PetscErrorCode ierr;
4285 
4286   PetscFunctionBegin;
4287   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4288   PetscValidPointer(dmSplit, 4);
4289   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4290   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4291   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4292   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4293   switch (dim) {
4294   case 2:
4295   case 3:
4296     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4297     break;
4298   default:
4299     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4300   }
4301   *dmSplit = sdm;
4302   PetscFunctionReturn(0);
4303 }
4304 
4305 #undef __FUNCT__
4306 #define __FUNCT__ "DMLabelCohesiveComplete"
4307 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4308 {
4309   IS              dimIS;
4310   const PetscInt *points;
4311   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4312   PetscErrorCode  ierr;
4313 
4314   PetscFunctionBegin;
4315   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4316   /* Cell orientation for face gives the side of the fault */
4317   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4318   if (!dimIS) PetscFunctionReturn(0);
4319   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4320   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4321   for (p = 0; p < numPoints; ++p) {
4322     const PetscInt *support;
4323     PetscInt        supportSize, s;
4324 
4325     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4326     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4327     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4328     for (s = 0; s < supportSize; ++s) {
4329       const PetscInt *cone, *ornt;
4330       PetscInt        coneSize, c;
4331       PetscBool       pos = PETSC_TRUE;
4332 
4333       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4334       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4335       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4336       for (c = 0; c < coneSize; ++c) {
4337         if (cone[c] == points[p]) {
4338           if (ornt[c] >= 0) {
4339             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4340           } else {
4341             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4342             pos  = PETSC_FALSE;
4343           }
4344           break;
4345         }
4346       }
4347       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4348       /* Put faces touching the fault in the label */
4349       for (c = 0; c < coneSize; ++c) {
4350         const PetscInt point = cone[c];
4351 
4352         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4353         if (val == -1) {
4354           PetscInt *closure = NULL;
4355           PetscInt  closureSize, cl;
4356 
4357           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4358           for (cl = 0; cl < closureSize*2; cl += 2) {
4359             const PetscInt clp = closure[cl];
4360 
4361             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4362             if ((val >= 0) && (val < dim-1)) {
4363               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4364               break;
4365             }
4366           }
4367           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4368         }
4369       }
4370     }
4371   }
4372   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4373   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4374   /* Search for other cells/faces/edges connected to the fault by a vertex */
4375   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4376   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4377   if (!dimIS) PetscFunctionReturn(0);
4378   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4379   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4380   for (p = 0; p < numPoints; ++p) {
4381     PetscInt *star = NULL;
4382     PetscInt  starSize, s;
4383     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4384 
4385     /* First mark cells connected to the fault */
4386     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4387     while (again) {
4388       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4389       again = 0;
4390       for (s = 0; s < starSize*2; s += 2) {
4391         const PetscInt  point = star[s];
4392         const PetscInt *cone;
4393         PetscInt        coneSize, c;
4394 
4395         if ((point < cStart) || (point >= cEnd)) continue;
4396         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4397         if (val != -1) continue;
4398         again = 2;
4399         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4400         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4401         for (c = 0; c < coneSize; ++c) {
4402           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4403           if (val != -1) {
4404             if (abs(val) < shift) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4405             if (val > 0) {
4406               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4407             } else {
4408               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4409             }
4410             again = 1;
4411             break;
4412           }
4413         }
4414       }
4415     }
4416     /* Classify the rest by cell membership */
4417     for (s = 0; s < starSize*2; s += 2) {
4418       const PetscInt point = star[s];
4419 
4420       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4421       if (val == -1) {
4422         PetscInt  *sstar = NULL;
4423         PetscInt   sstarSize, ss;
4424         PetscBool  marked = PETSC_FALSE;
4425 
4426         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4427         for (ss = 0; ss < sstarSize*2; ss += 2) {
4428           const PetscInt spoint = sstar[ss];
4429 
4430           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4431           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4432           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4433           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4434           if (val > 0) {
4435             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4436           } else {
4437             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4438           }
4439           marked = PETSC_TRUE;
4440           break;
4441         }
4442         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4443         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4444       }
4445     }
4446     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4447   }
4448   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4449   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4450   PetscFunctionReturn(0);
4451 }
4452 
4453 #undef __FUNCT__
4454 #define __FUNCT__ "DMPlexInterpolate_2D"
4455 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4456 {
4457   DM             idm;
4458   DM_Plex       *mesh;
4459   PetscHashIJ    edgeTable;
4460   PetscInt      *off;
4461   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4462   PetscInt       numEdges, firstEdge, edge, e;
4463   PetscErrorCode ierr;
4464 
4465   PetscFunctionBegin;
4466   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4467   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4468   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4469   numCells    = cEnd - cStart;
4470   numVertices = vEnd - vStart;
4471   firstEdge   = numCells + numVertices;
4472   numEdges    = 0;
4473   /* Count edges using algorithm from CreateNeighborCSR */
4474   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4475   if (off) {
4476     PetscInt numCorners = 0;
4477 
4478     numEdges = off[numCells]/2;
4479 #if 0
4480     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4481     numEdges += 3*numCells - off[numCells];
4482 #else
4483     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4484     for (c = cStart; c < cEnd; ++c) {
4485       PetscInt coneSize;
4486 
4487       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4488       numCorners += coneSize;
4489     }
4490     numEdges += numCorners - off[numCells];
4491 #endif
4492   }
4493 #if 0
4494   /* Check Euler characteristic V - E + F = 1 */
4495   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4496 #endif
4497   /* Create interpolated mesh */
4498   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4499   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4500   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4501   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4502   for (c = 0; c < numCells; ++c) {
4503     PetscInt numCorners;
4504 
4505     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4506     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4507   }
4508   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4509     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4510   }
4511   ierr = DMSetUp(idm);CHKERRQ(ierr);
4512   /* Get edge cones from subsets of cell vertices */
4513   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4514   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4515 
4516   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4517     const PetscInt *cellFaces;
4518     PetscInt        numCellFaces, faceSize, cf;
4519 
4520     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4521     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4522     for (cf = 0; cf < numCellFaces; ++cf) {
4523 #if 1
4524       PetscHashIJKey key;
4525 
4526       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4527       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4528       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4529       if (e < 0) {
4530         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4531         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4532         e    = edge++;
4533       }
4534 #else
4535       PetscBool found = PETSC_FALSE;
4536 
4537       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4538       for (e = firstEdge; e < edge; ++e) {
4539         const PetscInt *cone;
4540 
4541         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4542         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4543             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4544           found = PETSC_TRUE;
4545           break;
4546         }
4547       }
4548       if (!found) {
4549         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4550         ++edge;
4551       }
4552 #endif
4553       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4554     }
4555   }
4556   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4557   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4558   ierr = PetscFree(off);CHKERRQ(ierr);
4559   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4560   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4561   mesh = (DM_Plex*) (idm)->data;
4562   /* Orient edges */
4563   for (c = 0; c < numCells; ++c) {
4564     const PetscInt *cone = NULL, *cellFaces;
4565     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4566 
4567     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4568     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4569     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4570     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4571     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4572     for (cf = 0; cf < numCellFaces; ++cf) {
4573       const PetscInt *econe = NULL;
4574       PetscInt        esize;
4575 
4576       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4577       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4578       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4579       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4580         /* Correctly oriented */
4581         mesh->coneOrientations[coff+cf] = 0;
4582       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4583         /* Start at index 1, and reverse orientation */
4584         mesh->coneOrientations[coff+cf] = -(1+1);
4585       }
4586     }
4587   }
4588   *dmInt = idm;
4589   PetscFunctionReturn(0);
4590 }
4591 
4592 #undef __FUNCT__
4593 #define __FUNCT__ "DMPlexInterpolate_3D"
4594 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4595 {
4596   DM             idm, fdm;
4597   DM_Plex       *mesh;
4598   PetscInt      *off;
4599   const PetscInt numCorners = 4;
4600   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4601   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4602   PetscErrorCode ierr;
4603 
4604   PetscFunctionBegin;
4605   {
4606     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4607     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4608     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4609   }
4610   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4611   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4612   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4613   numCells    = cEnd - cStart;
4614   numVertices = vEnd - vStart;
4615   firstFace   = numCells + numVertices;
4616   numFaces    = 0;
4617   /* Count faces using algorithm from CreateNeighborCSR */
4618   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4619   if (off) {
4620     numFaces = off[numCells]/2;
4621     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4622     numFaces += 4*numCells - off[numCells];
4623   }
4624   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4625   firstEdge = firstFace + numFaces;
4626   numEdges  = numVertices + numFaces - numCells - 1;
4627   /* Create interpolated mesh */
4628   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4629   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4630   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4631   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4632   for (c = 0; c < numCells; ++c) {
4633     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4634   }
4635   for (f = firstFace; f < firstFace+numFaces; ++f) {
4636     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4637   }
4638   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4639     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4640   }
4641   ierr = DMSetUp(idm);CHKERRQ(ierr);
4642   /* Get face cones from subsets of cell vertices */
4643   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4644   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4645   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4646   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4647   for (f = firstFace; f < firstFace+numFaces; ++f) {
4648     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4649   }
4650   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4651   for (c = 0, face = firstFace; c < numCells; ++c) {
4652     const PetscInt *cellFaces;
4653     PetscInt        numCellFaces, faceSize, cf;
4654 
4655     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4656     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4657     for (cf = 0; cf < numCellFaces; ++cf) {
4658       PetscBool found = PETSC_FALSE;
4659 
4660       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4661       for (f = firstFace; f < face; ++f) {
4662         const PetscInt *cone = NULL;
4663 
4664         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4665         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4669             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4670             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4671           found = PETSC_TRUE;
4672           break;
4673         }
4674       }
4675       if (!found) {
4676         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4677         /* Save the vertices for orientation calculation */
4678         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4679         ++face;
4680       }
4681       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4682     }
4683   }
4684   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4685   /* Get edge cones from subsets of face vertices */
4686   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4687     const PetscInt *cellFaces;
4688     PetscInt        numCellFaces, faceSize, cf;
4689 
4690     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4691     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4692     for (cf = 0; cf < numCellFaces; ++cf) {
4693       PetscBool found = PETSC_FALSE;
4694 
4695       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4696       for (e = firstEdge; e < edge; ++e) {
4697         const PetscInt *cone = NULL;
4698 
4699         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4700         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4701             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4702           found = PETSC_TRUE;
4703           break;
4704         }
4705       }
4706       if (!found) {
4707         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4708         ++edge;
4709       }
4710       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4711     }
4712   }
4713   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4714   ierr = PetscFree(off);CHKERRQ(ierr);
4715   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4716   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4717   mesh = (DM_Plex*) (idm)->data;
4718   /* Orient edges */
4719   for (f = firstFace; f < firstFace+numFaces; ++f) {
4720     const PetscInt *cone, *cellFaces;
4721     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4722 
4723     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4724     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4725     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4726     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4727     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4728     for (cf = 0; cf < numCellFaces; ++cf) {
4729       const PetscInt *econe;
4730       PetscInt        esize;
4731 
4732       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4733       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4734       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4735       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4736         /* Correctly oriented */
4737         mesh->coneOrientations[coff+cf] = 0;
4738       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4739         /* Start at index 1, and reverse orientation */
4740         mesh->coneOrientations[coff+cf] = -(1+1);
4741       }
4742     }
4743   }
4744   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4745   /* Orient faces */
4746   for (c = 0; c < numCells; ++c) {
4747     const PetscInt *cone, *cellFaces;
4748     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4749 
4750     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4751     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4752     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4753     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4754     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4755     for (cf = 0; cf < numCellFaces; ++cf) {
4756       PetscInt *origClosure = NULL, *closure;
4757       PetscInt closureSize, i;
4758 
4759       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4760       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4761       for (i = 4; i < 7; ++i) {
4762         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4763       }
4764       closure = &origClosure[4*2];
4765       /* Remember that this is the orientation for edges, not vertices */
4766       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4767         /* Correctly oriented */
4768         mesh->coneOrientations[coff+cf] = 0;
4769       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4770         /* Shifted by 1 */
4771         mesh->coneOrientations[coff+cf] = 1;
4772       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4773         /* Shifted by 2 */
4774         mesh->coneOrientations[coff+cf] = 2;
4775       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4776         /* Start at edge 1, and reverse orientation */
4777         mesh->coneOrientations[coff+cf] = -(1+1);
4778       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4779         /* Start at index 0, and reverse orientation */
4780         mesh->coneOrientations[coff+cf] = -(0+1);
4781       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4782         /* Start at index 2, and reverse orientation */
4783         mesh->coneOrientations[coff+cf] = -(2+1);
4784       } else SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4785       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4786     }
4787   }
4788   {
4789     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4790     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4791     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4792   }
4793   *dmInt = idm;
4794   PetscFunctionReturn(0);
4795 }
4796 
4797 #undef __FUNCT__
4798 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4799 /*
4800   This takes as input the common mesh generator output, a list of the vertices for each cell
4801 */
4802 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4803 {
4804   PetscInt      *cone, c, p;
4805   PetscErrorCode ierr;
4806 
4807   PetscFunctionBegin;
4808   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4809   for (c = 0; c < numCells; ++c) {
4810     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4811   }
4812   ierr = DMSetUp(dm);CHKERRQ(ierr);
4813   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4814   for (c = 0; c < numCells; ++c) {
4815     for (p = 0; p < numCorners; ++p) {
4816       cone[p] = cells[c*numCorners+p]+numCells;
4817     }
4818     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4819   }
4820   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4821   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4822   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4823   PetscFunctionReturn(0);
4824 }
4825 
4826 #undef __FUNCT__
4827 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4828 /*
4829   This takes as input the coordinates for each vertex
4830 */
4831 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4832 {
4833   PetscSection   coordSection;
4834   Vec            coordinates;
4835   PetscScalar   *coords;
4836   PetscInt       coordSize, v, d;
4837   PetscErrorCode ierr;
4838 
4839   PetscFunctionBegin;
4840   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4841   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4842   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4843   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4844   for (v = numCells; v < numCells+numVertices; ++v) {
4845     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4846     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4847   }
4848   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4849   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4850   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4851   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4852   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4853   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4854   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4855   for (v = 0; v < numVertices; ++v) {
4856     for (d = 0; d < spaceDim; ++d) {
4857       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4858     }
4859   }
4860   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4861   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4862   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4863   PetscFunctionReturn(0);
4864 }
4865 
4866 #undef __FUNCT__
4867 #define __FUNCT__ "DMPlexCreateFromCellList"
4868 /*
4869   This takes as input the common mesh generator output, a list of the vertices for each cell
4870 */
4871 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4872 {
4873   PetscErrorCode ierr;
4874 
4875   PetscFunctionBegin;
4876   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4877   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4878   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4879   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4880   if (interpolate) {
4881     DM idm;
4882 
4883     switch (dim) {
4884     case 2:
4885       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4886     case 3:
4887       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4888     default:
4889       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4890     }
4891     ierr = DMDestroy(dm);CHKERRQ(ierr);
4892     *dm  = idm;
4893   }
4894   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4895   PetscFunctionReturn(0);
4896 }
4897 
4898 #if defined(PETSC_HAVE_TRIANGLE)
4899 #include <triangle.h>
4900 
4901 #undef __FUNCT__
4902 #define __FUNCT__ "InitInput_Triangle"
4903 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4904 {
4905   PetscFunctionBegin;
4906   inputCtx->numberofpoints             = 0;
4907   inputCtx->numberofpointattributes    = 0;
4908   inputCtx->pointlist                  = NULL;
4909   inputCtx->pointattributelist         = NULL;
4910   inputCtx->pointmarkerlist            = NULL;
4911   inputCtx->numberofsegments           = 0;
4912   inputCtx->segmentlist                = NULL;
4913   inputCtx->segmentmarkerlist          = NULL;
4914   inputCtx->numberoftriangleattributes = 0;
4915   inputCtx->trianglelist               = NULL;
4916   inputCtx->numberofholes              = 0;
4917   inputCtx->holelist                   = NULL;
4918   inputCtx->numberofregions            = 0;
4919   inputCtx->regionlist                 = NULL;
4920   PetscFunctionReturn(0);
4921 }
4922 
4923 #undef __FUNCT__
4924 #define __FUNCT__ "InitOutput_Triangle"
4925 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4926 {
4927   PetscFunctionBegin;
4928   outputCtx->numberofpoints        = 0;
4929   outputCtx->pointlist             = NULL;
4930   outputCtx->pointattributelist    = NULL;
4931   outputCtx->pointmarkerlist       = NULL;
4932   outputCtx->numberoftriangles     = 0;
4933   outputCtx->trianglelist          = NULL;
4934   outputCtx->triangleattributelist = NULL;
4935   outputCtx->neighborlist          = NULL;
4936   outputCtx->segmentlist           = NULL;
4937   outputCtx->segmentmarkerlist     = NULL;
4938   outputCtx->numberofedges         = 0;
4939   outputCtx->edgelist              = NULL;
4940   outputCtx->edgemarkerlist        = NULL;
4941   PetscFunctionReturn(0);
4942 }
4943 
4944 #undef __FUNCT__
4945 #define __FUNCT__ "FiniOutput_Triangle"
4946 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4947 {
4948   PetscFunctionBegin;
4949   free(outputCtx->pointmarkerlist);
4950   free(outputCtx->edgelist);
4951   free(outputCtx->edgemarkerlist);
4952   free(outputCtx->trianglelist);
4953   free(outputCtx->neighborlist);
4954   PetscFunctionReturn(0);
4955 }
4956 
4957 #undef __FUNCT__
4958 #define __FUNCT__ "DMPlexGenerate_Triangle"
4959 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4960 {
4961   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4962   PetscInt             dim              = 2;
4963   const PetscBool      createConvexHull = PETSC_FALSE;
4964   const PetscBool      constrained      = PETSC_FALSE;
4965   struct triangulateio in;
4966   struct triangulateio out;
4967   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4968   PetscMPIInt          rank;
4969   PetscErrorCode       ierr;
4970 
4971   PetscFunctionBegin;
4972   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4973   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4974   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4975   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4976 
4977   in.numberofpoints = vEnd - vStart;
4978   if (in.numberofpoints > 0) {
4979     PetscSection coordSection;
4980     Vec          coordinates;
4981     PetscScalar *array;
4982 
4983     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4984     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4985     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4986     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4987     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4988     for (v = vStart; v < vEnd; ++v) {
4989       const PetscInt idx = v - vStart;
4990       PetscInt       off, d;
4991 
4992       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4993       for (d = 0; d < dim; ++d) {
4994         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4995       }
4996       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4997     }
4998     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4999   }
5000   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5001   in.numberofsegments = eEnd - eStart;
5002   if (in.numberofsegments > 0) {
5003     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5004     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5005     for (e = eStart; e < eEnd; ++e) {
5006       const PetscInt  idx = e - eStart;
5007       const PetscInt *cone;
5008 
5009       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5010 
5011       in.segmentlist[idx*2+0] = cone[0] - vStart;
5012       in.segmentlist[idx*2+1] = cone[1] - vStart;
5013 
5014       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5015     }
5016   }
5017 #if 0 /* Do not currently support holes */
5018   PetscReal *holeCoords;
5019   PetscInt   h, d;
5020 
5021   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5022   if (in.numberofholes > 0) {
5023     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5024     for (h = 0; h < in.numberofholes; ++h) {
5025       for (d = 0; d < dim; ++d) {
5026         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5027       }
5028     }
5029   }
5030 #endif
5031   if (!rank) {
5032     char args[32];
5033 
5034     /* Take away 'Q' for verbose output */
5035     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5036     if (createConvexHull) {
5037       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5038     }
5039     if (constrained) {
5040       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5041     }
5042     triangulate(args, &in, &out, NULL);
5043   }
5044   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5047   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5048   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5049 
5050   {
5051     const PetscInt numCorners  = 3;
5052     const PetscInt numCells    = out.numberoftriangles;
5053     const PetscInt numVertices = out.numberofpoints;
5054     const int     *cells      = out.trianglelist;
5055     const double  *meshCoords = out.pointlist;
5056 
5057     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5058     /* Set labels */
5059     for (v = 0; v < numVertices; ++v) {
5060       if (out.pointmarkerlist[v]) {
5061         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5062       }
5063     }
5064     if (interpolate) {
5065       for (e = 0; e < out.numberofedges; e++) {
5066         if (out.edgemarkerlist[e]) {
5067           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5068           const PetscInt *edges;
5069           PetscInt        numEdges;
5070 
5071           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5072           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5073           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5074           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5075         }
5076       }
5077     }
5078     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5079   }
5080 #if 0 /* Do not currently support holes */
5081   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5082 #endif
5083   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5084   PetscFunctionReturn(0);
5085 }
5086 
5087 #undef __FUNCT__
5088 #define __FUNCT__ "DMPlexRefine_Triangle"
5089 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5090 {
5091   MPI_Comm             comm = ((PetscObject) dm)->comm;
5092   PetscInt             dim  = 2;
5093   struct triangulateio in;
5094   struct triangulateio out;
5095   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5096   PetscMPIInt          rank;
5097   PetscErrorCode       ierr;
5098 
5099   PetscFunctionBegin;
5100   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5101   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5102   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5103   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5104   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5105   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5106 
5107   in.numberofpoints = vEnd - vStart;
5108   if (in.numberofpoints > 0) {
5109     PetscSection coordSection;
5110     Vec          coordinates;
5111     PetscScalar *array;
5112 
5113     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5114     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5115     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5116     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5117     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5118     for (v = vStart; v < vEnd; ++v) {
5119       const PetscInt idx = v - vStart;
5120       PetscInt       off, d;
5121 
5122       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5123       for (d = 0; d < dim; ++d) {
5124         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5125       }
5126       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5127     }
5128     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5129   }
5130   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5131 
5132   in.numberofcorners   = 3;
5133   in.numberoftriangles = cEnd - cStart;
5134 
5135   in.trianglearealist  = (double*) maxVolumes;
5136   if (in.numberoftriangles > 0) {
5137     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5138     for (c = cStart; c < cEnd; ++c) {
5139       const PetscInt idx      = c - cStart;
5140       PetscInt      *closure = NULL;
5141       PetscInt       closureSize;
5142 
5143       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5144       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5145       for (v = 0; v < 3; ++v) {
5146         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5147       }
5148       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5149     }
5150   }
5151   /* TODO: Segment markers are missing on input */
5152 #if 0 /* Do not currently support holes */
5153   PetscReal *holeCoords;
5154   PetscInt   h, d;
5155 
5156   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5157   if (in.numberofholes > 0) {
5158     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5159     for (h = 0; h < in.numberofholes; ++h) {
5160       for (d = 0; d < dim; ++d) {
5161         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5162       }
5163     }
5164   }
5165 #endif
5166   if (!rank) {
5167     char args[32];
5168 
5169     /* Take away 'Q' for verbose output */
5170     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5171     triangulate(args, &in, &out, NULL);
5172   }
5173   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5176   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5177   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5178 
5179   {
5180     const PetscInt numCorners  = 3;
5181     const PetscInt numCells    = out.numberoftriangles;
5182     const PetscInt numVertices = out.numberofpoints;
5183     const int     *cells      = out.trianglelist;
5184     const double  *meshCoords = out.pointlist;
5185     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5186 
5187     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5188     /* Set labels */
5189     for (v = 0; v < numVertices; ++v) {
5190       if (out.pointmarkerlist[v]) {
5191         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5192       }
5193     }
5194     if (interpolate) {
5195       PetscInt e;
5196 
5197       for (e = 0; e < out.numberofedges; e++) {
5198         if (out.edgemarkerlist[e]) {
5199           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5200           const PetscInt *edges;
5201           PetscInt        numEdges;
5202 
5203           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5204           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5205           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5206           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5207         }
5208       }
5209     }
5210     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5211   }
5212 #if 0 /* Do not currently support holes */
5213   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5214 #endif
5215   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5216   PetscFunctionReturn(0);
5217 }
5218 #endif
5219 
5220 #if defined(PETSC_HAVE_TETGEN)
5221 #include <tetgen.h>
5222 #undef __FUNCT__
5223 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5224 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5225 {
5226   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5227   const PetscInt dim  = 3;
5228   ::tetgenio     in;
5229   ::tetgenio     out;
5230   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5231   PetscMPIInt    rank;
5232   PetscErrorCode ierr;
5233 
5234   PetscFunctionBegin;
5235   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5236   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5237   in.numberofpoints = vEnd - vStart;
5238   if (in.numberofpoints > 0) {
5239     PetscSection coordSection;
5240     Vec          coordinates;
5241     PetscScalar *array;
5242 
5243     in.pointlist       = new double[in.numberofpoints*dim];
5244     in.pointmarkerlist = new int[in.numberofpoints];
5245 
5246     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5247     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5248     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5249     for (v = vStart; v < vEnd; ++v) {
5250       const PetscInt idx = v - vStart;
5251       PetscInt       off, d;
5252 
5253       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5254       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5255       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5256     }
5257     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5258   }
5259   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5260 
5261   in.numberoffacets = fEnd - fStart;
5262   if (in.numberoffacets > 0) {
5263     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5264     in.facetmarkerlist = new int[in.numberoffacets];
5265     for (f = fStart; f < fEnd; ++f) {
5266       const PetscInt idx     = f - fStart;
5267       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
5268 
5269       in.facetlist[idx].numberofpolygons = 1;
5270       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5271       in.facetlist[idx].numberofholes    = 0;
5272       in.facetlist[idx].holelist         = NULL;
5273 
5274       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5275       for (p = 0; p < numPoints*2; p += 2) {
5276         const PetscInt point = points[p];
5277         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5278       }
5279 
5280       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5281       poly->numberofvertices = numVertices;
5282       poly->vertexlist       = new int[poly->numberofvertices];
5283       for (v = 0; v < numVertices; ++v) {
5284         const PetscInt vIdx = points[v] - vStart;
5285         poly->vertexlist[v] = vIdx;
5286       }
5287       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5288       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5289     }
5290   }
5291   if (!rank) {
5292     char args[32];
5293 
5294     /* Take away 'Q' for verbose output */
5295     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5296     ::tetrahedralize(args, &in, &out);
5297   }
5298   {
5299     const PetscInt numCorners  = 4;
5300     const PetscInt numCells    = out.numberoftetrahedra;
5301     const PetscInt numVertices = out.numberofpoints;
5302     const int     *cells      = out.tetrahedronlist;
5303     const double  *meshCoords = out.pointlist;
5304 
5305     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5306     /* Set labels */
5307     for (v = 0; v < numVertices; ++v) {
5308       if (out.pointmarkerlist[v]) {
5309         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5310       }
5311     }
5312     if (interpolate) {
5313       PetscInt e;
5314 
5315       for (e = 0; e < out.numberofedges; e++) {
5316         if (out.edgemarkerlist[e]) {
5317           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5318           const PetscInt *edges;
5319           PetscInt        numEdges;
5320 
5321           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5322           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5323           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5324           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5325         }
5326       }
5327       for (f = 0; f < out.numberoftrifaces; f++) {
5328         if (out.trifacemarkerlist[f]) {
5329           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5330           const PetscInt *faces;
5331           PetscInt        numFaces;
5332 
5333           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5334           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5335           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5336           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5337         }
5338       }
5339     }
5340     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5341   }
5342   PetscFunctionReturn(0);
5343 }
5344 
5345 #undef __FUNCT__
5346 #define __FUNCT__ "DMPlexRefine_Tetgen"
5347 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5348 {
5349   MPI_Comm       comm = ((PetscObject) dm)->comm;
5350   const PetscInt dim  = 3;
5351   ::tetgenio     in;
5352   ::tetgenio     out;
5353   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5354   PetscMPIInt    rank;
5355   PetscErrorCode ierr;
5356 
5357   PetscFunctionBegin;
5358   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5359   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5360   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5361   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5362 
5363   in.numberofpoints = vEnd - vStart;
5364   if (in.numberofpoints > 0) {
5365     PetscSection coordSection;
5366     Vec          coordinates;
5367     PetscScalar *array;
5368 
5369     in.pointlist       = new double[in.numberofpoints*dim];
5370     in.pointmarkerlist = new int[in.numberofpoints];
5371 
5372     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5373     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5374     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5375     for (v = vStart; v < vEnd; ++v) {
5376       const PetscInt idx = v - vStart;
5377       PetscInt       off, d;
5378 
5379       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5380       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5381       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5382     }
5383     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5384   }
5385   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5386 
5387   in.numberofcorners       = 4;
5388   in.numberoftetrahedra    = cEnd - cStart;
5389   in.tetrahedronvolumelist = (double*) maxVolumes;
5390   if (in.numberoftetrahedra > 0) {
5391     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5392     for (c = cStart; c < cEnd; ++c) {
5393       const PetscInt idx      = c - cStart;
5394       PetscInt      *closure = NULL;
5395       PetscInt       closureSize;
5396 
5397       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5398       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5399       for (v = 0; v < 4; ++v) {
5400         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5401       }
5402       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5403     }
5404   }
5405   /* TODO: Put in boundary faces with markers */
5406   if (!rank) {
5407     char args[32];
5408 
5409     /* Take away 'Q' for verbose output */
5410     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5411     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5412     ::tetrahedralize(args, &in, &out);
5413   }
5414   in.tetrahedronvolumelist = NULL;
5415 
5416   {
5417     const PetscInt numCorners  = 4;
5418     const PetscInt numCells    = out.numberoftetrahedra;
5419     const PetscInt numVertices = out.numberofpoints;
5420     const int     *cells      = out.tetrahedronlist;
5421     const double  *meshCoords = out.pointlist;
5422     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5423 
5424     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5425     /* Set labels */
5426     for (v = 0; v < numVertices; ++v) {
5427       if (out.pointmarkerlist[v]) {
5428         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5429       }
5430     }
5431     if (interpolate) {
5432       PetscInt e, f;
5433 
5434       for (e = 0; e < out.numberofedges; e++) {
5435         if (out.edgemarkerlist[e]) {
5436           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5437           const PetscInt *edges;
5438           PetscInt        numEdges;
5439 
5440           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5441           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5442           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5443           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5444         }
5445       }
5446       for (f = 0; f < out.numberoftrifaces; f++) {
5447         if (out.trifacemarkerlist[f]) {
5448           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5449           const PetscInt *faces;
5450           PetscInt        numFaces;
5451 
5452           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5453           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5454           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5455           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5456         }
5457       }
5458     }
5459     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5460   }
5461   PetscFunctionReturn(0);
5462 }
5463 #endif
5464 
5465 #if defined(PETSC_HAVE_CTETGEN)
5466 #include "ctetgen.h"
5467 
5468 #undef __FUNCT__
5469 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5470 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5471 {
5472   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5473   const PetscInt dim  = 3;
5474   PLC           *in, *out;
5475   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5476   PetscMPIInt    rank;
5477   PetscErrorCode ierr;
5478 
5479   PetscFunctionBegin;
5480   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5481   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5482   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5483   ierr = PLCCreate(&in);CHKERRQ(ierr);
5484   ierr = PLCCreate(&out);CHKERRQ(ierr);
5485 
5486   in->numberofpoints = vEnd - vStart;
5487   if (in->numberofpoints > 0) {
5488     PetscSection coordSection;
5489     Vec          coordinates;
5490     PetscScalar *array;
5491 
5492     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5493     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5494     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5495     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5496     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5497     for (v = vStart; v < vEnd; ++v) {
5498       const PetscInt idx = v - vStart;
5499       PetscInt       off, d, m;
5500 
5501       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5502       for (d = 0; d < dim; ++d) {
5503         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5504       }
5505       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5506 
5507       in->pointmarkerlist[idx] = (int) m;
5508     }
5509     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5510   }
5511   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5512 
5513   in->numberoffacets = fEnd - fStart;
5514   if (in->numberoffacets > 0) {
5515     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5516     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5517     for (f = fStart; f < fEnd; ++f) {
5518       const PetscInt idx     = f - fStart;
5519       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5520       polygon       *poly;
5521 
5522       in->facetlist[idx].numberofpolygons = 1;
5523 
5524       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5525 
5526       in->facetlist[idx].numberofholes    = 0;
5527       in->facetlist[idx].holelist         = NULL;
5528 
5529       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5530       for (p = 0; p < numPoints*2; p += 2) {
5531         const PetscInt point = points[p];
5532         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5533       }
5534 
5535       poly                   = in->facetlist[idx].polygonlist;
5536       poly->numberofvertices = numVertices;
5537       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5538       for (v = 0; v < numVertices; ++v) {
5539         const PetscInt vIdx = points[v] - vStart;
5540         poly->vertexlist[v] = vIdx;
5541       }
5542       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5543       in->facetmarkerlist[idx] = (int) m;
5544       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5545     }
5546   }
5547   if (!rank) {
5548     TetGenOpts t;
5549 
5550     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5551     t.in        = boundary; /* Should go away */
5552     t.plc       = 1;
5553     t.quality   = 1;
5554     t.edgesout  = 1;
5555     t.zeroindex = 1;
5556     t.quiet     = 1;
5557     t.verbose   = verbose;
5558     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5559     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5560   }
5561   {
5562     const PetscInt numCorners  = 4;
5563     const PetscInt numCells    = out->numberoftetrahedra;
5564     const PetscInt numVertices = out->numberofpoints;
5565     const int     *cells      = out->tetrahedronlist;
5566     const double  *meshCoords = out->pointlist;
5567 
5568     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5569     /* Set labels */
5570     for (v = 0; v < numVertices; ++v) {
5571       if (out->pointmarkerlist[v]) {
5572         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5573       }
5574     }
5575     if (interpolate) {
5576       PetscInt e;
5577 
5578       for (e = 0; e < out->numberofedges; e++) {
5579         if (out->edgemarkerlist[e]) {
5580           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5581           const PetscInt *edges;
5582           PetscInt        numEdges;
5583 
5584           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5585           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5586           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5587           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5588         }
5589       }
5590       for (f = 0; f < out->numberoftrifaces; f++) {
5591         if (out->trifacemarkerlist[f]) {
5592           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5593           const PetscInt *faces;
5594           PetscInt        numFaces;
5595 
5596           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5597           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5598           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5599           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5600         }
5601       }
5602     }
5603     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5604   }
5605 
5606   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5607   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5608   PetscFunctionReturn(0);
5609 }
5610 
5611 #undef __FUNCT__
5612 #define __FUNCT__ "DMPlexRefine_CTetgen"
5613 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5614 {
5615   MPI_Comm       comm = ((PetscObject) dm)->comm;
5616   const PetscInt dim  = 3;
5617   PLC           *in, *out;
5618   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5619   PetscMPIInt    rank;
5620   PetscErrorCode ierr;
5621 
5622   PetscFunctionBegin;
5623   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5624   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5626   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5627   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5628   ierr = PLCCreate(&in);CHKERRQ(ierr);
5629   ierr = PLCCreate(&out);CHKERRQ(ierr);
5630 
5631   in->numberofpoints = vEnd - vStart;
5632   if (in->numberofpoints > 0) {
5633     PetscSection coordSection;
5634     Vec          coordinates;
5635     PetscScalar *array;
5636 
5637     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5638     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5639     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5640     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5641     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5642     for (v = vStart; v < vEnd; ++v) {
5643       const PetscInt idx = v - vStart;
5644       PetscInt       off, d, m;
5645 
5646       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5647       for (d = 0; d < dim; ++d) {
5648         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5649       }
5650       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5651 
5652       in->pointmarkerlist[idx] = (int) m;
5653     }
5654     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5655   }
5656   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5657 
5658   in->numberofcorners       = 4;
5659   in->numberoftetrahedra    = cEnd - cStart;
5660   in->tetrahedronvolumelist = maxVolumes;
5661   if (in->numberoftetrahedra > 0) {
5662     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5663     for (c = cStart; c < cEnd; ++c) {
5664       const PetscInt idx      = c - cStart;
5665       PetscInt      *closure = NULL;
5666       PetscInt       closureSize;
5667 
5668       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5669       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5670       for (v = 0; v < 4; ++v) {
5671         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5672       }
5673       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5674     }
5675   }
5676   if (!rank) {
5677     TetGenOpts t;
5678 
5679     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5680 
5681     t.in        = dm; /* Should go away */
5682     t.refine    = 1;
5683     t.varvolume = 1;
5684     t.quality   = 1;
5685     t.edgesout  = 1;
5686     t.zeroindex = 1;
5687     t.quiet     = 1;
5688     t.verbose   = verbose; /* Change this */
5689 
5690     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5691     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5692   }
5693   {
5694     const PetscInt numCorners  = 4;
5695     const PetscInt numCells    = out->numberoftetrahedra;
5696     const PetscInt numVertices = out->numberofpoints;
5697     const int     *cells       = out->tetrahedronlist;
5698     const double  *meshCoords  = out->pointlist;
5699     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5700 
5701     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5702     /* Set labels */
5703     for (v = 0; v < numVertices; ++v) {
5704       if (out->pointmarkerlist[v]) {
5705         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5706       }
5707     }
5708     if (interpolate) {
5709       PetscInt e, f;
5710 
5711       for (e = 0; e < out->numberofedges; e++) {
5712         if (out->edgemarkerlist[e]) {
5713           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5714           const PetscInt *edges;
5715           PetscInt        numEdges;
5716 
5717           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5718           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5719           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5720           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5721         }
5722       }
5723       for (f = 0; f < out->numberoftrifaces; f++) {
5724         if (out->trifacemarkerlist[f]) {
5725           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5726           const PetscInt *faces;
5727           PetscInt        numFaces;
5728 
5729           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5730           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5731           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5732           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5733         }
5734       }
5735     }
5736     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5737   }
5738   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5739   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5740   PetscFunctionReturn(0);
5741 }
5742 #endif
5743 
5744 #undef __FUNCT__
5745 #define __FUNCT__ "DMPlexGenerate"
5746 /*@C
5747   DMPlexGenerate - Generates a mesh.
5748 
5749   Not Collective
5750 
5751   Input Parameters:
5752 + boundary - The DMPlex boundary object
5753 . name - The mesh generation package name
5754 - interpolate - Flag to create intermediate mesh elements
5755 
5756   Output Parameter:
5757 . mesh - The DMPlex object
5758 
5759   Level: intermediate
5760 
5761 .keywords: mesh, elements
5762 .seealso: DMPlexCreate(), DMRefine()
5763 @*/
5764 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5765 {
5766   PetscInt       dim;
5767   char           genname[1024];
5768   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5769   PetscErrorCode ierr;
5770 
5771   PetscFunctionBegin;
5772   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5773   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5774   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5775   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5776   if (flg) name = genname;
5777   if (name) {
5778     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5779     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5780     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5781   }
5782   switch (dim) {
5783   case 1:
5784     if (!name || isTriangle) {
5785 #if defined(PETSC_HAVE_TRIANGLE)
5786       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5787 #else
5788       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5789 #endif
5790     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5791     break;
5792   case 2:
5793     if (!name || isCTetgen) {
5794 #if defined(PETSC_HAVE_CTETGEN)
5795       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5796 #else
5797       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5798 #endif
5799     } else if (isTetgen) {
5800 #if defined(PETSC_HAVE_TETGEN)
5801       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5802 #else
5803       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5804 #endif
5805     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5806     break;
5807   default:
5808     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5809   }
5810   PetscFunctionReturn(0);
5811 }
5812 
5813 typedef PetscInt CellRefiner;
5814 
5815 #undef __FUNCT__
5816 #define __FUNCT__ "GetDepthStart_Private"
5817 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5818 {
5819   PetscFunctionBegin;
5820   if (cStart) *cStart = 0;
5821   if (vStart) *vStart = depthSize[depth];
5822   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5823   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5824   PetscFunctionReturn(0);
5825 }
5826 
5827 #undef __FUNCT__
5828 #define __FUNCT__ "GetDepthEnd_Private"
5829 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5830 {
5831   PetscFunctionBegin;
5832   if (cEnd) *cEnd = depthSize[depth];
5833   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5834   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5835   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5836   PetscFunctionReturn(0);
5837 }
5838 
5839 #undef __FUNCT__
5840 #define __FUNCT__ "CellRefinerGetSizes"
5841 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5842 {
5843   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5844   PetscErrorCode ierr;
5845 
5846   PetscFunctionBegin;
5847   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5850   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5851   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5852   switch (refiner) {
5853   case 1:
5854     /* Simplicial 2D */
5855     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5856     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5857     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5858     break;
5859   case 3:
5860     /* Hybrid 2D */
5861     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5862     cMax = PetscMin(cEnd, cMax);
5863     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5864     fMax         = PetscMin(fEnd, fMax);
5865     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5866     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 */
5867     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5868     break;
5869   case 2:
5870     /* Hex 2D */
5871     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5872     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5873     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5874     break;
5875   default:
5876     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5877   }
5878   PetscFunctionReturn(0);
5879 }
5880 
5881 #undef __FUNCT__
5882 #define __FUNCT__ "CellRefinerSetConeSizes"
5883 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5884 {
5885   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5886   PetscErrorCode ierr;
5887 
5888   PetscFunctionBegin;
5889   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5890   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5893   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5894   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5895   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5896   switch (refiner) {
5897   case 1:
5898     /* Simplicial 2D */
5899     /* All cells have 3 faces */
5900     for (c = cStart; c < cEnd; ++c) {
5901       for (r = 0; r < 4; ++r) {
5902         const PetscInt newp = (c - cStart)*4 + r;
5903 
5904         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5905       }
5906     }
5907     /* Split faces have 2 vertices and the same cells as the parent */
5908     for (f = fStart; f < fEnd; ++f) {
5909       for (r = 0; r < 2; ++r) {
5910         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5911         PetscInt       size;
5912 
5913         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5914         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5915         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5916       }
5917     }
5918     /* Interior faces have 2 vertices and 2 cells */
5919     for (c = cStart; c < cEnd; ++c) {
5920       for (r = 0; r < 3; ++r) {
5921         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5922 
5923         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5924         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5925       }
5926     }
5927     /* Old vertices have identical supports */
5928     for (v = vStart; v < vEnd; ++v) {
5929       const PetscInt newp = vStartNew + (v - vStart);
5930       PetscInt       size;
5931 
5932       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5933       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5934     }
5935     /* Face vertices have 2 + cells*2 supports */
5936     for (f = fStart; f < fEnd; ++f) {
5937       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5938       PetscInt       size;
5939 
5940       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5941       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5942     }
5943     break;
5944   case 2:
5945     /* Hex 2D */
5946     /* All cells have 4 faces */
5947     for (c = cStart; c < cEnd; ++c) {
5948       for (r = 0; r < 4; ++r) {
5949         const PetscInt newp = (c - cStart)*4 + r;
5950 
5951         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5952       }
5953     }
5954     /* Split faces have 2 vertices and the same cells as the parent */
5955     for (f = fStart; f < fEnd; ++f) {
5956       for (r = 0; r < 2; ++r) {
5957         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5958         PetscInt       size;
5959 
5960         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5961         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5962         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5963       }
5964     }
5965     /* Interior faces have 2 vertices and 2 cells */
5966     for (c = cStart; c < cEnd; ++c) {
5967       for (r = 0; r < 4; ++r) {
5968         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5969 
5970         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5971         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5972       }
5973     }
5974     /* Old vertices have identical supports */
5975     for (v = vStart; v < vEnd; ++v) {
5976       const PetscInt newp = vStartNew + (v - vStart);
5977       PetscInt       size;
5978 
5979       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5980       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5981     }
5982     /* Face vertices have 2 + cells supports */
5983     for (f = fStart; f < fEnd; ++f) {
5984       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5985       PetscInt       size;
5986 
5987       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5988       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5989     }
5990     /* Cell vertices have 4 supports */
5991     for (c = cStart; c < cEnd; ++c) {
5992       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5993 
5994       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5995     }
5996     break;
5997   case 3:
5998     /* Hybrid 2D */
5999     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6000     cMax = PetscMin(cEnd, cMax);
6001     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6002     fMax = PetscMin(fEnd, fMax);
6003     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6004     /* Interior cells have 3 faces */
6005     for (c = cStart; c < cMax; ++c) {
6006       for (r = 0; r < 4; ++r) {
6007         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6008 
6009         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6010       }
6011     }
6012     /* Hybrid cells have 4 faces */
6013     for (c = cMax; c < cEnd; ++c) {
6014       for (r = 0; r < 2; ++r) {
6015         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6016 
6017         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6018       }
6019     }
6020     /* Interior split faces have 2 vertices and the same cells as the parent */
6021     for (f = fStart; f < fMax; ++f) {
6022       for (r = 0; r < 2; ++r) {
6023         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6024         PetscInt       size;
6025 
6026         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6027         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6028         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6029       }
6030     }
6031     /* Interior cell faces have 2 vertices and 2 cells */
6032     for (c = cStart; c < cMax; ++c) {
6033       for (r = 0; r < 3; ++r) {
6034         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6035 
6036         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6037         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6038       }
6039     }
6040     /* Hybrid faces have 2 vertices and the same cells */
6041     for (f = fMax; f < fEnd; ++f) {
6042       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6043       PetscInt       size;
6044 
6045       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6046       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6047       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6048     }
6049     /* Hybrid cell faces have 2 vertices and 2 cells */
6050     for (c = cMax; c < cEnd; ++c) {
6051       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6052 
6053       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6054       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6055     }
6056     /* Old vertices have identical supports */
6057     for (v = vStart; v < vEnd; ++v) {
6058       const PetscInt newp = vStartNew + (v - vStart);
6059       PetscInt       size;
6060 
6061       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6062       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6063     }
6064     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6065     for (f = fStart; f < fMax; ++f) {
6066       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6067       const PetscInt *support;
6068       PetscInt       size, newSize = 2, s;
6069 
6070       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6071       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6072       for (s = 0; s < size; ++s) {
6073         if (support[s] >= cMax) newSize += 1;
6074         else newSize += 2;
6075       }
6076       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6077     }
6078     break;
6079   default:
6080     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6081   }
6082   PetscFunctionReturn(0);
6083 }
6084 
6085 #undef __FUNCT__
6086 #define __FUNCT__ "CellRefinerSetCones"
6087 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6088 {
6089   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;
6090   PetscInt       maxSupportSize, *supportRef;
6091   PetscErrorCode ierr;
6092 
6093   PetscFunctionBegin;
6094   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6095   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6098   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6099   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6100   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6101   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6102   switch (refiner) {
6103   case 1:
6104     /* Simplicial 2D */
6105     /*
6106      2
6107      |\
6108      | \
6109      |  \
6110      |   \
6111      | C  \
6112      |     \
6113      |      \
6114      2---1---1
6115      |\  D  / \
6116      | 2   0   \
6117      |A \ /  B  \
6118      0---0-------1
6119      */
6120     /* All cells have 3 faces */
6121     for (c = cStart; c < cEnd; ++c) {
6122       const PetscInt  newp = cStartNew + (c - cStart)*4;
6123       const PetscInt *cone, *ornt;
6124       PetscInt        coneNew[3], orntNew[3];
6125 
6126       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6127       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6128       /* A triangle */
6129       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6130       orntNew[0] = ornt[0];
6131       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6132       orntNew[1] = -2;
6133       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6134       orntNew[2] = ornt[2];
6135       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6136       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6137 #if 1
6138       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6139       for (p = 0; p < 3; ++p) {
6140         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6141       }
6142 #endif
6143       /* B triangle */
6144       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6145       orntNew[0] = ornt[0];
6146       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6147       orntNew[1] = ornt[1];
6148       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6149       orntNew[2] = -2;
6150       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6151       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6152 #if 1
6153       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6154       for (p = 0; p < 3; ++p) {
6155         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6156       }
6157 #endif
6158       /* C triangle */
6159       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6160       orntNew[0] = -2;
6161       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6162       orntNew[1] = ornt[1];
6163       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6164       orntNew[2] = ornt[2];
6165       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6166       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6167 #if 1
6168       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6169       for (p = 0; p < 3; ++p) {
6170         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6171       }
6172 #endif
6173       /* D triangle */
6174       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6175       orntNew[0] = 0;
6176       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6177       orntNew[1] = 0;
6178       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6179       orntNew[2] = 0;
6180       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6181       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6182 #if 1
6183       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6184       for (p = 0; p < 3; ++p) {
6185         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6186       }
6187 #endif
6188     }
6189     /* Split faces have 2 vertices and the same cells as the parent */
6190     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6191     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6192     for (f = fStart; f < fEnd; ++f) {
6193       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6194 
6195       for (r = 0; r < 2; ++r) {
6196         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6197         const PetscInt *cone, *support;
6198         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6199 
6200         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6201         coneNew[0]       = vStartNew + (cone[0] - vStart);
6202         coneNew[1]       = vStartNew + (cone[1] - vStart);
6203         coneNew[(r+1)%2] = newv;
6204         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6205 #if 1
6206         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6207         for (p = 0; p < 2; ++p) {
6208           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6209         }
6210 #endif
6211         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6212         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6213         for (s = 0; s < supportSize; ++s) {
6214           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6215           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6216           for (c = 0; c < coneSize; ++c) {
6217             if (cone[c] == f) break;
6218           }
6219           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6220         }
6221         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6222 #if 1
6223         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6224         for (p = 0; p < supportSize; ++p) {
6225           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6226         }
6227 #endif
6228       }
6229     }
6230     /* Interior faces have 2 vertices and 2 cells */
6231     for (c = cStart; c < cEnd; ++c) {
6232       const PetscInt *cone;
6233 
6234       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6235       for (r = 0; r < 3; ++r) {
6236         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6237         PetscInt       coneNew[2];
6238         PetscInt       supportNew[2];
6239 
6240         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6241         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6242         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6243 #if 1
6244         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6245         for (p = 0; p < 2; ++p) {
6246           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6247         }
6248 #endif
6249         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6250         supportNew[1] = (c - cStart)*4 + 3;
6251         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6252 #if 1
6253         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6254         for (p = 0; p < 2; ++p) {
6255           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6256         }
6257 #endif
6258       }
6259     }
6260     /* Old vertices have identical supports */
6261     for (v = vStart; v < vEnd; ++v) {
6262       const PetscInt  newp = vStartNew + (v - vStart);
6263       const PetscInt *support, *cone;
6264       PetscInt        size, s;
6265 
6266       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6267       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6268       for (s = 0; s < size; ++s) {
6269         PetscInt r = 0;
6270 
6271         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6272         if (cone[1] == v) r = 1;
6273         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6274       }
6275       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6276 #if 1
6277       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6278       for (p = 0; p < size; ++p) {
6279         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6280       }
6281 #endif
6282     }
6283     /* Face vertices have 2 + cells*2 supports */
6284     for (f = fStart; f < fEnd; ++f) {
6285       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6286       const PetscInt *cone, *support;
6287       PetscInt        size, s;
6288 
6289       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6290       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6291       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6292       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6293       for (s = 0; s < size; ++s) {
6294         PetscInt r = 0;
6295 
6296         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6297         if      (cone[1] == f) r = 1;
6298         else if (cone[2] == f) r = 2;
6299         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6300         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6301       }
6302       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6303 #if 1
6304       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6305       for (p = 0; p < 2+size*2; ++p) {
6306         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6307       }
6308 #endif
6309     }
6310     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6311     break;
6312   case 2:
6313     /* Hex 2D */
6314     /*
6315      3---------2---------2
6316      |         |         |
6317      |    D    2    C    |
6318      |         |         |
6319      3----3----0----1----1
6320      |         |         |
6321      |    A    0    B    |
6322      |         |         |
6323      0---------0---------1
6324      */
6325     /* All cells have 4 faces */
6326     for (c = cStart; c < cEnd; ++c) {
6327       const PetscInt  newp = (c - cStart)*4;
6328       const PetscInt *cone, *ornt;
6329       PetscInt        coneNew[4], orntNew[4];
6330 
6331       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6332       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6333       /* A quad */
6334       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6335       orntNew[0] = ornt[0];
6336       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6337       orntNew[1] = 0;
6338       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6339       orntNew[2] = -2;
6340       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6341       orntNew[3] = ornt[3];
6342       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6343       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6344 #if 1
6345       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6346       for (p = 0; p < 4; ++p) {
6347         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6348       }
6349 #endif
6350       /* B quad */
6351       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6352       orntNew[0] = ornt[0];
6353       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6354       orntNew[1] = ornt[1];
6355       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6356       orntNew[2] = 0;
6357       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6358       orntNew[3] = -2;
6359       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6360       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6361 #if 1
6362       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6363       for (p = 0; p < 4; ++p) {
6364         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6365       }
6366 #endif
6367       /* C quad */
6368       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6369       orntNew[0] = -2;
6370       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6371       orntNew[1] = ornt[1];
6372       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6373       orntNew[2] = ornt[2];
6374       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6375       orntNew[3] = 0;
6376       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6377       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6378 #if 1
6379       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6380       for (p = 0; p < 4; ++p) {
6381         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6382       }
6383 #endif
6384       /* D quad */
6385       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6386       orntNew[0] = 0;
6387       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6388       orntNew[1] = -2;
6389       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6390       orntNew[2] = ornt[2];
6391       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6392       orntNew[3] = ornt[3];
6393       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6394       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6395 #if 1
6396       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6397       for (p = 0; p < 4; ++p) {
6398         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6399       }
6400 #endif
6401     }
6402     /* Split faces have 2 vertices and the same cells as the parent */
6403     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6404     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6405     for (f = fStart; f < fEnd; ++f) {
6406       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6407 
6408       for (r = 0; r < 2; ++r) {
6409         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6410         const PetscInt *cone, *support;
6411         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6412 
6413         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6414         coneNew[0]       = vStartNew + (cone[0] - vStart);
6415         coneNew[1]       = vStartNew + (cone[1] - vStart);
6416         coneNew[(r+1)%2] = newv;
6417         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6418 #if 1
6419         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6420         for (p = 0; p < 2; ++p) {
6421           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6422         }
6423 #endif
6424         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6425         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6426         for (s = 0; s < supportSize; ++s) {
6427           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6428           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6429           for (c = 0; c < coneSize; ++c) {
6430             if (cone[c] == f) break;
6431           }
6432           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6433         }
6434         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6435 #if 1
6436         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6437         for (p = 0; p < supportSize; ++p) {
6438           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6439         }
6440 #endif
6441       }
6442     }
6443     /* Interior faces have 2 vertices and 2 cells */
6444     for (c = cStart; c < cEnd; ++c) {
6445       const PetscInt *cone;
6446       PetscInt        coneNew[2], supportNew[2];
6447 
6448       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6449       for (r = 0; r < 4; ++r) {
6450         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6451 
6452         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6453         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6454         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6455 #if 1
6456         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, 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(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6459         }
6460 #endif
6461         supportNew[0] = (c - cStart)*4 + r;
6462         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6463         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6464 #if 1
6465         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, 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(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6468         }
6469 #endif
6470       }
6471     }
6472     /* Old vertices have identical supports */
6473     for (v = vStart; v < vEnd; ++v) {
6474       const PetscInt  newp = vStartNew + (v - vStart);
6475       const PetscInt *support, *cone;
6476       PetscInt        size, s;
6477 
6478       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6479       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6480       for (s = 0; s < size; ++s) {
6481         PetscInt r = 0;
6482 
6483         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6484         if (cone[1] == v) r = 1;
6485         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6486       }
6487       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6488 #if 1
6489       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6490       for (p = 0; p < size; ++p) {
6491         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6492       }
6493 #endif
6494     }
6495     /* Face vertices have 2 + cells supports */
6496     for (f = fStart; f < fEnd; ++f) {
6497       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6498       const PetscInt *cone, *support;
6499       PetscInt        size, s;
6500 
6501       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6502       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6503       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6504       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6505       for (s = 0; s < size; ++s) {
6506         PetscInt r = 0;
6507 
6508         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6509         if      (cone[1] == f) r = 1;
6510         else if (cone[2] == f) r = 2;
6511         else if (cone[3] == f) r = 3;
6512         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6513       }
6514       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6515 #if 1
6516       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6517       for (p = 0; p < 2+size; ++p) {
6518         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6519       }
6520 #endif
6521     }
6522     /* Cell vertices have 4 supports */
6523     for (c = cStart; c < cEnd; ++c) {
6524       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6525       PetscInt       supportNew[4];
6526 
6527       for (r = 0; r < 4; ++r) {
6528         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6529       }
6530       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6531     }
6532     break;
6533   case 3:
6534     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6535     cMax = PetscMin(cEnd, cMax);
6536     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6537     fMax = PetscMin(fEnd, fMax);
6538     /* Interior cells have 3 faces */
6539     for (c = cStart; c < cMax; ++c) {
6540       const PetscInt  newp = cStartNew + (c - cStart)*4;
6541       const PetscInt *cone, *ornt;
6542       PetscInt        coneNew[3], orntNew[3];
6543 
6544       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6545       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6546       /* A triangle */
6547       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6548       orntNew[0] = ornt[0];
6549       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6550       orntNew[1] = -2;
6551       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6552       orntNew[2] = ornt[2];
6553       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6554       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6555 #if 1
6556       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6557       for (p = 0; p < 3; ++p) {
6558         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6559       }
6560 #endif
6561       /* B triangle */
6562       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6563       orntNew[0] = ornt[0];
6564       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6565       orntNew[1] = ornt[1];
6566       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6567       orntNew[2] = -2;
6568       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6569       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6570 #if 1
6571       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6572       for (p = 0; p < 3; ++p) {
6573         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6574       }
6575 #endif
6576       /* C triangle */
6577       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6578       orntNew[0] = -2;
6579       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6580       orntNew[1] = ornt[1];
6581       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6582       orntNew[2] = ornt[2];
6583       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6584       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6585 #if 1
6586       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6587       for (p = 0; p < 3; ++p) {
6588         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6589       }
6590 #endif
6591       /* D triangle */
6592       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6593       orntNew[0] = 0;
6594       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6595       orntNew[1] = 0;
6596       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6597       orntNew[2] = 0;
6598       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6599       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6600 #if 1
6601       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6602       for (p = 0; p < 3; ++p) {
6603         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6604       }
6605 #endif
6606     }
6607     /*
6608      2----3----3
6609      |         |
6610      |    B    |
6611      |         |
6612      0----4--- 1
6613      |         |
6614      |    A    |
6615      |         |
6616      0----2----1
6617      */
6618     /* Hybrid cells have 4 faces */
6619     for (c = cMax; c < cEnd; ++c) {
6620       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6621       const PetscInt *cone, *ornt;
6622       PetscInt        coneNew[4], orntNew[4];
6623 
6624       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6625       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6626       /* A quad */
6627       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6628       orntNew[0] = ornt[0];
6629       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6630       orntNew[1] = ornt[1];
6631       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6632       orntNew[2] = 0;
6633       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6634       orntNew[3] = 0;
6635       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6636       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6637 #if 1
6638       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6639       for (p = 0; p < 4; ++p) {
6640         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6641       }
6642 #endif
6643       /* B quad */
6644       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6645       orntNew[0] = ornt[0];
6646       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6647       orntNew[1] = ornt[1];
6648       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6649       orntNew[2] = 0;
6650       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6651       orntNew[3] = 0;
6652       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6653       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6654 #if 1
6655       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6656       for (p = 0; p < 4; ++p) {
6657         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6658       }
6659 #endif
6660     }
6661     /* Interior split faces have 2 vertices and the same cells as the parent */
6662     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6663     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6664     for (f = fStart; f < fMax; ++f) {
6665       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6666 
6667       for (r = 0; r < 2; ++r) {
6668         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6669         const PetscInt *cone, *support;
6670         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6671 
6672         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6673         coneNew[0]       = vStartNew + (cone[0] - vStart);
6674         coneNew[1]       = vStartNew + (cone[1] - vStart);
6675         coneNew[(r+1)%2] = newv;
6676         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6677 #if 1
6678         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6679         for (p = 0; p < 2; ++p) {
6680           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6681         }
6682 #endif
6683         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6684         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6685         for (s = 0; s < supportSize; ++s) {
6686           if (support[s] >= cMax) {
6687             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6688           } else {
6689             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6690             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6691             for (c = 0; c < coneSize; ++c) {
6692               if (cone[c] == f) break;
6693             }
6694             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6695           }
6696         }
6697         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6698 #if 1
6699         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6700         for (p = 0; p < supportSize; ++p) {
6701           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6702         }
6703 #endif
6704       }
6705     }
6706     /* Interior cell faces have 2 vertices and 2 cells */
6707     for (c = cStart; c < cMax; ++c) {
6708       const PetscInt *cone;
6709 
6710       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6711       for (r = 0; r < 3; ++r) {
6712         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6713         PetscInt       coneNew[2];
6714         PetscInt       supportNew[2];
6715 
6716         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6717         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6718         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6719 #if 1
6720         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6721         for (p = 0; p < 2; ++p) {
6722           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6723         }
6724 #endif
6725         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6726         supportNew[1] = (c - cStart)*4 + 3;
6727         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6728 #if 1
6729         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6730         for (p = 0; p < 2; ++p) {
6731           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6732         }
6733 #endif
6734       }
6735     }
6736     /* Interior hybrid faces have 2 vertices and the same cells */
6737     for (f = fMax; f < fEnd; ++f) {
6738       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6739       const PetscInt *cone;
6740       const PetscInt *support;
6741       PetscInt        coneNew[2];
6742       PetscInt        supportNew[2];
6743       PetscInt        size, s, r;
6744 
6745       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6746       coneNew[0] = vStartNew + (cone[0] - vStart);
6747       coneNew[1] = vStartNew + (cone[1] - vStart);
6748       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6749 #if 1
6750       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6751       for (p = 0; p < 2; ++p) {
6752         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6753       }
6754 #endif
6755       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6756       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6757       for (s = 0; s < size; ++s) {
6758         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6759         for (r = 0; r < 2; ++r) {
6760           if (cone[r+2] == f) break;
6761         }
6762         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6763       }
6764       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6765 #if 1
6766       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6767       for (p = 0; p < size; ++p) {
6768         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6769       }
6770 #endif
6771     }
6772     /* Cell hybrid faces have 2 vertices and 2 cells */
6773     for (c = cMax; c < cEnd; ++c) {
6774       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6775       const PetscInt *cone;
6776       PetscInt        coneNew[2];
6777       PetscInt        supportNew[2];
6778 
6779       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6780       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6781       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6782       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6783 #if 1
6784       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6785       for (p = 0; p < 2; ++p) {
6786         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6787       }
6788 #endif
6789       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6790       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6791       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6792 #if 1
6793       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6794       for (p = 0; p < 2; ++p) {
6795         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6796       }
6797 #endif
6798     }
6799     /* Old vertices have identical supports */
6800     for (v = vStart; v < vEnd; ++v) {
6801       const PetscInt  newp = vStartNew + (v - vStart);
6802       const PetscInt *support, *cone;
6803       PetscInt        size, s;
6804 
6805       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6806       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6807       for (s = 0; s < size; ++s) {
6808         if (support[s] >= fMax) {
6809           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6810         } else {
6811           PetscInt r = 0;
6812 
6813           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6814           if (cone[1] == v) r = 1;
6815           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6816         }
6817       }
6818       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6819 #if 1
6820       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6821       for (p = 0; p < size; ++p) {
6822         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6823       }
6824 #endif
6825     }
6826     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6827     for (f = fStart; f < fMax; ++f) {
6828       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6829       const PetscInt *cone, *support;
6830       PetscInt        size, newSize = 2, s;
6831 
6832       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6833       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6834       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6835       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6836       for (s = 0; s < size; ++s) {
6837         PetscInt r = 0;
6838 
6839         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6840         if (support[s] >= cMax) {
6841           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6842 
6843           newSize += 1;
6844         } else {
6845           if      (cone[1] == f) r = 1;
6846           else if (cone[2] == f) r = 2;
6847           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6848           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6849 
6850           newSize += 2;
6851         }
6852       }
6853       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6854 #if 1
6855       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6856       for (p = 0; p < newSize; ++p) {
6857         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6858       }
6859 #endif
6860     }
6861     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6862     break;
6863   default:
6864     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6865   }
6866   PetscFunctionReturn(0);
6867 }
6868 
6869 #undef __FUNCT__
6870 #define __FUNCT__ "CellRefinerSetCoordinates"
6871 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6872 {
6873   PetscSection   coordSection, coordSectionNew;
6874   Vec            coordinates, coordinatesNew;
6875   PetscScalar   *coords, *coordsNew;
6876   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6877   PetscErrorCode ierr;
6878 
6879   PetscFunctionBegin;
6880   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6881   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6882   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6884   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6885   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6886   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6887   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6888   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6889   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6890   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6891   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6892   if (fMax < 0) fMax = fEnd;
6893   switch (refiner) {
6894   case 1:
6895   case 2:
6896   case 3:
6897     /* Simplicial and Hex 2D */
6898     /* All vertices have the dim coordinates */
6899     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6900       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6901       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6902     }
6903     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6904     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6905     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6906     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6907     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6908     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6909     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6910     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6911     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6912     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6913     /* Old vertices have the same coordinates */
6914     for (v = vStart; v < vEnd; ++v) {
6915       const PetscInt newv = vStartNew + (v - vStart);
6916       PetscInt       off, offnew, d;
6917 
6918       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6919       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6920       for (d = 0; d < dim; ++d) {
6921         coordsNew[offnew+d] = coords[off+d];
6922       }
6923     }
6924     /* Face vertices have the average of endpoint coordinates */
6925     for (f = fStart; f < fMax; ++f) {
6926       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6927       const PetscInt *cone;
6928       PetscInt        coneSize, offA, offB, offnew, d;
6929 
6930       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6931       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6932       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6934       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6935       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6936       for (d = 0; d < dim; ++d) {
6937         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6938       }
6939     }
6940     /* Just Hex 2D */
6941     if (refiner == 2) {
6942       /* Cell vertices have the average of corner coordinates */
6943       for (c = cStart; c < cEnd; ++c) {
6944         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6945         PetscInt      *cone = NULL;
6946         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6947 
6948         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6949         for (p = 0; p < closureSize*2; p += 2) {
6950           const PetscInt point = cone[p];
6951           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6952         }
6953         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6954         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6957         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6958         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6959         for (d = 0; d < dim; ++d) {
6960           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6961         }
6962         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6963       }
6964     }
6965     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6966     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6967     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6968     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6969     break;
6970   default:
6971     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6972   }
6973   PetscFunctionReturn(0);
6974 }
6975 
6976 #undef __FUNCT__
6977 #define __FUNCT__ "DMPlexCreateProcessSF"
6978 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6979 {
6980   PetscInt           numRoots, numLeaves, l;
6981   const PetscInt    *localPoints;
6982   const PetscSFNode *remotePoints;
6983   PetscInt          *localPointsNew;
6984   PetscSFNode       *remotePointsNew;
6985   PetscInt          *ranks, *ranksNew;
6986   PetscErrorCode     ierr;
6987 
6988   PetscFunctionBegin;
6989   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6990   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6991   for (l = 0; l < numLeaves; ++l) {
6992     ranks[l] = remotePoints[l].rank;
6993   }
6994   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6996   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6997   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6998   for (l = 0; l < numLeaves; ++l) {
6999     ranksNew[l]              = ranks[l];
7000     localPointsNew[l]        = l;
7001     remotePointsNew[l].index = 0;
7002     remotePointsNew[l].rank  = ranksNew[l];
7003   }
7004   ierr = PetscFree(ranks);CHKERRQ(ierr);
7005   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7006   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7007   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7008   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7009   PetscFunctionReturn(0);
7010 }
7011 
7012 #undef __FUNCT__
7013 #define __FUNCT__ "CellRefinerCreateSF"
7014 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7015 {
7016   PetscSF            sf, sfNew, sfProcess;
7017   IS                 processRanks;
7018   MPI_Datatype       depthType;
7019   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7020   const PetscInt    *localPoints, *neighbors;
7021   const PetscSFNode *remotePoints;
7022   PetscInt          *localPointsNew;
7023   PetscSFNode       *remotePointsNew;
7024   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7025   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7026   PetscErrorCode     ierr;
7027 
7028   PetscFunctionBegin;
7029   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7031   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7034   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7035   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7036   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7037   switch (refiner) {
7038   case 3:
7039     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7040     cMax = PetscMin(cEnd, cMax);
7041     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7042     fMax = PetscMin(fEnd, fMax);
7043   }
7044   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7045   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7046   /* Caculate size of new SF */
7047   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7048   if (numRoots < 0) PetscFunctionReturn(0);
7049   for (l = 0; l < numLeaves; ++l) {
7050     const PetscInt p = localPoints[l];
7051 
7052     switch (refiner) {
7053     case 1:
7054       /* Simplicial 2D */
7055       if ((p >= vStart) && (p < vEnd)) {
7056         /* Old vertices stay the same */
7057         ++numLeavesNew;
7058       } else if ((p >= fStart) && (p < fEnd)) {
7059         /* Old faces add new faces and vertex */
7060         numLeavesNew += 1 + 2;
7061       } else if ((p >= cStart) && (p < cEnd)) {
7062         /* Old cells add new cells and interior faces */
7063         numLeavesNew += 4 + 3;
7064       }
7065       break;
7066     case 2:
7067       /* Hex 2D */
7068       if ((p >= vStart) && (p < vEnd)) {
7069         /* Old vertices stay the same */
7070         ++numLeavesNew;
7071       } else if ((p >= fStart) && (p < fEnd)) {
7072         /* Old faces add new faces and vertex */
7073         numLeavesNew += 1 + 2;
7074       } else if ((p >= cStart) && (p < cEnd)) {
7075         /* Old cells add new cells and interior faces */
7076         numLeavesNew += 4 + 4;
7077       }
7078       break;
7079     default:
7080       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7081     }
7082   }
7083   /* Communicate depthSizes for each remote rank */
7084   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7085   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7086   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7087   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);
7088   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7089   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7090   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7091   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7092   for (n = 0; n < numNeighbors; ++n) {
7093     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7094   }
7095   depthSizeOld[depth]   = cMax;
7096   depthSizeOld[0]       = vMax;
7097   depthSizeOld[depth-1] = fMax;
7098   depthSizeOld[1]       = eMax;
7099 
7100   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7101   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7102 
7103   depthSizeOld[depth]   = cEnd - cStart;
7104   depthSizeOld[0]       = vEnd - vStart;
7105   depthSizeOld[depth-1] = fEnd - fStart;
7106   depthSizeOld[1]       = eEnd - eStart;
7107 
7108   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7109   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7110   for (n = 0; n < numNeighbors; ++n) {
7111     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7112   }
7113   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7114   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7115   /* Calculate new point SF */
7116   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7117   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7118   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7119   for (l = 0, m = 0; l < numLeaves; ++l) {
7120     PetscInt    p     = localPoints[l];
7121     PetscInt    rp    = remotePoints[l].index, n;
7122     PetscMPIInt rrank = remotePoints[l].rank;
7123 
7124     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7125     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7126     switch (refiner) {
7127     case 1:
7128       /* Simplicial 2D */
7129       if ((p >= vStart) && (p < vEnd)) {
7130         /* Old vertices stay the same */
7131         localPointsNew[m]        = vStartNew     + (p  - vStart);
7132         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7133         remotePointsNew[m].rank  = rrank;
7134         ++m;
7135       } else if ((p >= fStart) && (p < fEnd)) {
7136         /* Old faces add new faces and vertex */
7137         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7138         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7139         remotePointsNew[m].rank  = rrank;
7140         ++m;
7141         for (r = 0; r < 2; ++r, ++m) {
7142           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7143           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7144           remotePointsNew[m].rank  = rrank;
7145         }
7146       } else if ((p >= cStart) && (p < cEnd)) {
7147         /* Old cells add new cells and interior faces */
7148         for (r = 0; r < 4; ++r, ++m) {
7149           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7150           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7151           remotePointsNew[m].rank  = rrank;
7152         }
7153         for (r = 0; r < 3; ++r, ++m) {
7154           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7155           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7156           remotePointsNew[m].rank  = rrank;
7157         }
7158       }
7159       break;
7160     case 2:
7161       /* Hex 2D */
7162       if ((p >= vStart) && (p < vEnd)) {
7163         /* Old vertices stay the same */
7164         localPointsNew[m]        = vStartNew     + (p  - vStart);
7165         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7166         remotePointsNew[m].rank  = rrank;
7167         ++m;
7168       } else if ((p >= fStart) && (p < fEnd)) {
7169         /* Old faces add new faces and vertex */
7170         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7171         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7172         remotePointsNew[m].rank  = rrank;
7173         ++m;
7174         for (r = 0; r < 2; ++r, ++m) {
7175           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7176           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7177           remotePointsNew[m].rank  = rrank;
7178         }
7179       } else if ((p >= cStart) && (p < cEnd)) {
7180         /* Old cells add new cells and interior faces */
7181         for (r = 0; r < 4; ++r, ++m) {
7182           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7183           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7184           remotePointsNew[m].rank  = rrank;
7185         }
7186         for (r = 0; r < 4; ++r, ++m) {
7187           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7188           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7189           remotePointsNew[m].rank  = rrank;
7190         }
7191       }
7192       break;
7193     case 3:
7194       /* Hybrid simplicial 2D */
7195       if ((p >= vStart) && (p < vEnd)) {
7196         /* Old vertices stay the same */
7197         localPointsNew[m]        = vStartNew     + (p  - vStart);
7198         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7199         remotePointsNew[m].rank  = rrank;
7200         ++m;
7201       } else if ((p >= fStart) && (p < fMax)) {
7202         /* Old interior faces add new faces and vertex */
7203         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7204         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7205         remotePointsNew[m].rank  = rrank;
7206         ++m;
7207         for (r = 0; r < 2; ++r, ++m) {
7208           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7209           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7210           remotePointsNew[m].rank  = rrank;
7211         }
7212       } else if ((p >= fMax) && (p < fEnd)) {
7213         /* Old hybrid faces stay the same */
7214         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7215         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7216         remotePointsNew[m].rank  = rrank;
7217         ++m;
7218       } else if ((p >= cStart) && (p < cMax)) {
7219         /* Old interior cells add new cells and interior faces */
7220         for (r = 0; r < 4; ++r, ++m) {
7221           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7222           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7223           remotePointsNew[m].rank  = rrank;
7224         }
7225         for (r = 0; r < 3; ++r, ++m) {
7226           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7227           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7228           remotePointsNew[m].rank  = rrank;
7229         }
7230       } else if ((p >= cStart) && (p < cMax)) {
7231         /* Old hybrid cells add new cells and hybrid face */
7232         for (r = 0; r < 2; ++r, ++m) {
7233           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7234           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7235           remotePointsNew[m].rank  = rrank;
7236         }
7237         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7238         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]);
7239         remotePointsNew[m].rank  = rrank;
7240         ++m;
7241       }
7242       break;
7243     default:
7244       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7245     }
7246   }
7247   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7248   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7249   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7250   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7251   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7252   PetscFunctionReturn(0);
7253 }
7254 
7255 #undef __FUNCT__
7256 #define __FUNCT__ "CellRefinerCreateLabels"
7257 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7258 {
7259   PetscInt       numLabels, l;
7260   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7261   PetscErrorCode ierr;
7262 
7263   PetscFunctionBegin;
7264   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7266   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7267   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7268 
7269   cStartNew = 0;
7270   vStartNew = depthSize[2];
7271   fStartNew = depthSize[2] + depthSize[0];
7272 
7273   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7274   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7275   switch (refiner) {
7276   case 3:
7277     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7278     cMax = PetscMin(cEnd, cMax);
7279     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7280     fMax = PetscMin(fEnd, fMax);
7281   }
7282   for (l = 0; l < numLabels; ++l) {
7283     DMLabel         label, labelNew;
7284     const char     *lname;
7285     PetscBool       isDepth;
7286     IS              valueIS;
7287     const PetscInt *values;
7288     PetscInt        numValues, val;
7289 
7290     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7291     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7292     if (isDepth) continue;
7293     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7294     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7295     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7296     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7297     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7298     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7299     for (val = 0; val < numValues; ++val) {
7300       IS              pointIS;
7301       const PetscInt *points;
7302       PetscInt        numPoints, n;
7303 
7304       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7305       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7306       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7307       for (n = 0; n < numPoints; ++n) {
7308         const PetscInt p = points[n];
7309         switch (refiner) {
7310         case 1:
7311           /* Simplicial 2D */
7312           if ((p >= vStart) && (p < vEnd)) {
7313             /* Old vertices stay the same */
7314             newp = vStartNew + (p - vStart);
7315             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7316           } else if ((p >= fStart) && (p < fEnd)) {
7317             /* Old faces add new faces and vertex */
7318             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7319             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7320             for (r = 0; r < 2; ++r) {
7321               newp = fStartNew + (p - fStart)*2 + r;
7322               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7323             }
7324           } else if ((p >= cStart) && (p < cEnd)) {
7325             /* Old cells add new cells and interior faces */
7326             for (r = 0; r < 4; ++r) {
7327               newp = cStartNew + (p - cStart)*4 + r;
7328               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7329             }
7330             for (r = 0; r < 3; ++r) {
7331               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7332               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7333             }
7334           }
7335           break;
7336         case 2:
7337           /* Hex 2D */
7338           if ((p >= vStart) && (p < vEnd)) {
7339             /* Old vertices stay the same */
7340             newp = vStartNew + (p - vStart);
7341             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7342           } else if ((p >= fStart) && (p < fEnd)) {
7343             /* Old faces add new faces and vertex */
7344             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7345             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7346             for (r = 0; r < 2; ++r) {
7347               newp = fStartNew + (p - fStart)*2 + r;
7348               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7349             }
7350           } else if ((p >= cStart) && (p < cEnd)) {
7351             /* Old cells add new cells and interior faces and vertex */
7352             for (r = 0; r < 4; ++r) {
7353               newp = cStartNew + (p - cStart)*4 + r;
7354               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7355             }
7356             for (r = 0; r < 4; ++r) {
7357               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7358               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7359             }
7360             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7362           }
7363           break;
7364         case 3:
7365           /* Hybrid simplicial 2D */
7366           if ((p >= vStart) && (p < vEnd)) {
7367             /* Old vertices stay the same */
7368             newp = vStartNew + (p - vStart);
7369             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7370           } else if ((p >= fStart) && (p < fMax)) {
7371             /* Old interior faces add new faces and vertex */
7372             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7373             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7374             for (r = 0; r < 2; ++r) {
7375               newp = fStartNew + (p - fStart)*2 + r;
7376               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7377             }
7378           } else if ((p >= fMax) && (p < fEnd)) {
7379             /* Old hybrid faces stay the same */
7380             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7381             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7382           } else if ((p >= cStart) && (p < cMax)) {
7383             /* Old interior cells add new cells and interior faces */
7384             for (r = 0; r < 4; ++r) {
7385               newp = cStartNew + (p - cStart)*4 + r;
7386               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7387             }
7388             for (r = 0; r < 3; ++r) {
7389               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7390               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7391             }
7392           } else if ((p >= cMax) && (p < cEnd)) {
7393             /* Old hybrid cells add new cells and hybrid face */
7394             for (r = 0; r < 2; ++r) {
7395               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7396               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7397             }
7398             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7399             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7400           }
7401           break;
7402         default:
7403           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7404         }
7405       }
7406       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7407       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7408     }
7409     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7410     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7411     if (0) {
7412       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7413       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7414       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7415     }
7416   }
7417   PetscFunctionReturn(0);
7418 }
7419 
7420 #undef __FUNCT__
7421 #define __FUNCT__ "DMPlexRefine_Uniform"
7422 /* This will only work for interpolated meshes */
7423 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7424 {
7425   DM             rdm;
7426   PetscInt      *depthSize;
7427   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7428   PetscErrorCode ierr;
7429 
7430   PetscFunctionBegin;
7431   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7432   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7433   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7434   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7435   /* Calculate number of new points of each depth */
7436   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7437   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7438   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7439   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7440   /* Step 1: Set chart */
7441   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7442   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7443   /* Step 2: Set cone/support sizes */
7444   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7445   /* Step 3: Setup refined DM */
7446   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7447   /* Step 4: Set cones and supports */
7448   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7449   /* Step 5: Stratify */
7450   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7451   /* Step 6: Set coordinates for vertices */
7452   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7453   /* Step 7: Create pointSF */
7454   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7455   /* Step 8: Create labels */
7456   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7457   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7458 
7459   *dmRefined = rdm;
7460   PetscFunctionReturn(0);
7461 }
7462 
7463 #undef __FUNCT__
7464 #define __FUNCT__ "DMPlexSetRefinementUniform"
7465 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7466 {
7467   DM_Plex *mesh = (DM_Plex*) dm->data;
7468 
7469   PetscFunctionBegin;
7470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7471   mesh->refinementUniform = refinementUniform;
7472   PetscFunctionReturn(0);
7473 }
7474 
7475 #undef __FUNCT__
7476 #define __FUNCT__ "DMPlexGetRefinementUniform"
7477 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7478 {
7479   DM_Plex *mesh = (DM_Plex*) dm->data;
7480 
7481   PetscFunctionBegin;
7482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7483   PetscValidPointer(refinementUniform,  2);
7484   *refinementUniform = mesh->refinementUniform;
7485   PetscFunctionReturn(0);
7486 }
7487 
7488 #undef __FUNCT__
7489 #define __FUNCT__ "DMPlexSetRefinementLimit"
7490 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7491 {
7492   DM_Plex *mesh = (DM_Plex*) dm->data;
7493 
7494   PetscFunctionBegin;
7495   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7496   mesh->refinementLimit = refinementLimit;
7497   PetscFunctionReturn(0);
7498 }
7499 
7500 #undef __FUNCT__
7501 #define __FUNCT__ "DMPlexGetRefinementLimit"
7502 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7503 {
7504   DM_Plex *mesh = (DM_Plex*) dm->data;
7505 
7506   PetscFunctionBegin;
7507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7508   PetscValidPointer(refinementLimit,  2);
7509   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7510   *refinementLimit = mesh->refinementLimit;
7511   PetscFunctionReturn(0);
7512 }
7513 
7514 #undef __FUNCT__
7515 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7516 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7517 {
7518   PetscInt       dim, cStart, coneSize, cMax;
7519   PetscErrorCode ierr;
7520 
7521   PetscFunctionBegin;
7522   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7523   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7524   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7525   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7526   switch (dim) {
7527   case 2:
7528     switch (coneSize) {
7529     case 3:
7530       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7531       else *cellRefiner = 1; /* Triangular */
7532       break;
7533     case 4:
7534       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7535       else *cellRefiner = 2; /* Quadrilateral */
7536       break;
7537     default:
7538       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7539     }
7540     break;
7541   default:
7542     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7543   }
7544   PetscFunctionReturn(0);
7545 }
7546 
7547 #undef __FUNCT__
7548 #define __FUNCT__ "DMRefine_Plex"
7549 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7550 {
7551   PetscReal      refinementLimit;
7552   PetscInt       dim, cStart, cEnd;
7553   char           genname[1024], *name = NULL;
7554   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7555   PetscErrorCode ierr;
7556 
7557   PetscFunctionBegin;
7558   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7559   if (isUniform) {
7560     CellRefiner cellRefiner;
7561 
7562     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7563     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7564     PetscFunctionReturn(0);
7565   }
7566   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7567   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7569   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7570   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7571   if (flg) name = genname;
7572   if (name) {
7573     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7574     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7575     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7576   }
7577   switch (dim) {
7578   case 2:
7579     if (!name || isTriangle) {
7580 #if defined(PETSC_HAVE_TRIANGLE)
7581       double  *maxVolumes;
7582       PetscInt c;
7583 
7584       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7585       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7586       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7587 #else
7588       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7589 #endif
7590     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7591     break;
7592   case 3:
7593     if (!name || isCTetgen) {
7594 #if defined(PETSC_HAVE_CTETGEN)
7595       PetscReal *maxVolumes;
7596       PetscInt   c;
7597 
7598       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7599       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7600       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7601 #else
7602       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7603 #endif
7604     } else if (isTetgen) {
7605 #if defined(PETSC_HAVE_TETGEN)
7606       double  *maxVolumes;
7607       PetscInt c;
7608 
7609       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7610       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7611       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7612 #else
7613       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7614 #endif
7615     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7616     break;
7617   default:
7618     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7619   }
7620   PetscFunctionReturn(0);
7621 }
7622 
7623 #undef __FUNCT__
7624 #define __FUNCT__ "DMPlexGetDepth"
7625 /*@
7626   DMPlexGetDepth - get the number of strata
7627 
7628   Not Collective
7629 
7630   Input Parameters:
7631 . dm           - The DMPlex object
7632 
7633   Output Parameters:
7634 . depth - number of strata
7635 
7636   Level: developer
7637 
7638   Notes:
7639   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7640 
7641 .keywords: mesh, points
7642 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7643 @*/
7644 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7645 {
7646   PetscInt       d;
7647   PetscErrorCode ierr;
7648 
7649   PetscFunctionBegin;
7650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7651   PetscValidPointer(depth, 2);
7652   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7653   *depth = d-1;
7654   PetscFunctionReturn(0);
7655 }
7656 
7657 #undef __FUNCT__
7658 #define __FUNCT__ "DMPlexGetDepthStratum"
7659 /*@
7660   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7661 
7662   Not Collective
7663 
7664   Input Parameters:
7665 + dm           - The DMPlex object
7666 - stratumValue - The requested depth
7667 
7668   Output Parameters:
7669 + start - The first point at this depth
7670 - end   - One beyond the last point at this depth
7671 
7672   Level: developer
7673 
7674 .keywords: mesh, points
7675 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7676 @*/
7677 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7678 {
7679   DM_Plex       *mesh = (DM_Plex*) dm->data;
7680   DMLabel        next  = mesh->labels;
7681   PetscBool      flg   = PETSC_FALSE;
7682   PetscInt       depth;
7683   PetscErrorCode ierr;
7684 
7685   PetscFunctionBegin;
7686   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7687   if (stratumValue < 0) {
7688     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7689     PetscFunctionReturn(0);
7690   } else {
7691     PetscInt pStart, pEnd;
7692 
7693     if (start) *start = 0;
7694     if (end)   *end   = 0;
7695     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7696     if (pStart == pEnd) PetscFunctionReturn(0);
7697   }
7698   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7699   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7700   /* We should have a generic GetLabel() and a Label class */
7701   while (next) {
7702     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7703     if (flg) break;
7704     next = next->next;
7705   }
7706   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7707   depth = stratumValue;
7708   if ((depth < 0) || (depth >= next->numStrata)) {
7709     if (start) *start = 0;
7710     if (end)   *end   = 0;
7711   } else {
7712     if (start) *start = next->points[next->stratumOffsets[depth]];
7713     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7714   }
7715   PetscFunctionReturn(0);
7716 }
7717 
7718 #undef __FUNCT__
7719 #define __FUNCT__ "DMPlexGetHeightStratum"
7720 /*@
7721   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7722 
7723   Not Collective
7724 
7725   Input Parameters:
7726 + dm           - The DMPlex object
7727 - stratumValue - The requested height
7728 
7729   Output Parameters:
7730 + start - The first point at this height
7731 - end   - One beyond the last point at this height
7732 
7733   Level: developer
7734 
7735 .keywords: mesh, points
7736 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7737 @*/
7738 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7739 {
7740   DM_Plex       *mesh = (DM_Plex*) dm->data;
7741   DMLabel        next  = mesh->labels;
7742   PetscBool      flg   = PETSC_FALSE;
7743   PetscInt       depth;
7744   PetscErrorCode ierr;
7745 
7746   PetscFunctionBegin;
7747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7748   if (stratumValue < 0) {
7749     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7750   } else {
7751     PetscInt pStart, pEnd;
7752 
7753     if (start) *start = 0;
7754     if (end)   *end   = 0;
7755     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7756     if (pStart == pEnd) PetscFunctionReturn(0);
7757   }
7758   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7759   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7760   /* We should have a generic GetLabel() and a Label class */
7761   while (next) {
7762     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7763     if (flg) break;
7764     next = next->next;
7765   }
7766   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7767   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7768   if ((depth < 0) || (depth >= next->numStrata)) {
7769     if (start) *start = 0;
7770     if (end)   *end   = 0;
7771   } else {
7772     if (start) *start = next->points[next->stratumOffsets[depth]];
7773     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7774   }
7775   PetscFunctionReturn(0);
7776 }
7777 
7778 #undef __FUNCT__
7779 #define __FUNCT__ "DMPlexCreateSectionInitial"
7780 /* Set the number of dof on each point and separate by fields */
7781 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7782 {
7783   PetscInt      *numDofTot;
7784   PetscInt       pStart = 0, pEnd = 0;
7785   PetscInt       p, d, f;
7786   PetscErrorCode ierr;
7787 
7788   PetscFunctionBegin;
7789   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7790   for (d = 0; d <= dim; ++d) {
7791     numDofTot[d] = 0;
7792     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7793   }
7794   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7795   if (numFields > 0) {
7796     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7797     if (numComp) {
7798       for (f = 0; f < numFields; ++f) {
7799         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7800       }
7801     }
7802   }
7803   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7804   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7805   for (d = 0; d <= dim; ++d) {
7806     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7807     for (p = pStart; p < pEnd; ++p) {
7808       for (f = 0; f < numFields; ++f) {
7809         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7810       }
7811       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7812     }
7813   }
7814   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7815   PetscFunctionReturn(0);
7816 }
7817 
7818 #undef __FUNCT__
7819 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7820 /* Set the number of dof on each point and separate by fields
7821    If constDof is PETSC_DETERMINE, constrain every dof on the point
7822 */
7823 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7824 {
7825   PetscInt       numFields;
7826   PetscInt       bc;
7827   PetscErrorCode ierr;
7828 
7829   PetscFunctionBegin;
7830   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7831   for (bc = 0; bc < numBC; ++bc) {
7832     PetscInt        field = 0;
7833     const PetscInt *idx;
7834     PetscInt        n, i;
7835 
7836     if (numFields) field = bcField[bc];
7837     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7838     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7839     for (i = 0; i < n; ++i) {
7840       const PetscInt p        = idx[i];
7841       PetscInt       numConst = constDof;
7842 
7843       /* Constrain every dof on the point */
7844       if (numConst < 0) {
7845         if (numFields) {
7846           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7847         } else {
7848           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7849         }
7850       }
7851       if (numFields) {
7852         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7853       }
7854       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7855     }
7856     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7857   }
7858   PetscFunctionReturn(0);
7859 }
7860 
7861 #undef __FUNCT__
7862 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7863 /* Set the constrained indices on each point and separate by fields */
7864 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7865 {
7866   PetscInt      *maxConstraints;
7867   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7868   PetscErrorCode ierr;
7869 
7870   PetscFunctionBegin;
7871   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7872   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7873   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7874   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7875   for (p = pStart; p < pEnd; ++p) {
7876     PetscInt cdof;
7877 
7878     if (numFields) {
7879       for (f = 0; f < numFields; ++f) {
7880         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7881         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7882       }
7883     } else {
7884       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7885       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7886     }
7887   }
7888   for (f = 0; f < numFields; ++f) {
7889     maxConstraints[numFields] += maxConstraints[f];
7890   }
7891   if (maxConstraints[numFields]) {
7892     PetscInt *indices;
7893 
7894     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7895     for (p = pStart; p < pEnd; ++p) {
7896       PetscInt cdof, d;
7897 
7898       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7899       if (cdof) {
7900         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7901         if (numFields) {
7902           PetscInt numConst = 0, foff = 0;
7903 
7904           for (f = 0; f < numFields; ++f) {
7905             PetscInt cfdof, fdof;
7906 
7907             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7908             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7909             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7910             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7911             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7912             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7913             numConst += cfdof;
7914             foff     += fdof;
7915           }
7916           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7917         } else {
7918           for (d = 0; d < cdof; ++d) indices[d] = d;
7919         }
7920         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7921       }
7922     }
7923     ierr = PetscFree(indices);CHKERRQ(ierr);
7924   }
7925   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7926   PetscFunctionReturn(0);
7927 }
7928 
7929 #undef __FUNCT__
7930 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7931 /* Set the constrained field indices on each point */
7932 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7933 {
7934   const PetscInt *points, *indices;
7935   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7936   PetscErrorCode  ierr;
7937 
7938   PetscFunctionBegin;
7939   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7940   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7941 
7942   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7943   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7944   if (!constraintIndices) {
7945     PetscInt *idx, i;
7946 
7947     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7948     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7949     for (i = 0; i < maxDof; ++i) idx[i] = i;
7950     for (p = 0; p < numPoints; ++p) {
7951       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7952     }
7953     ierr = PetscFree(idx);CHKERRQ(ierr);
7954   } else {
7955     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7956     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7957     for (p = 0; p < numPoints; ++p) {
7958       PetscInt fcdof;
7959 
7960       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7961       if (fcdof != numConstraints) SETERRQ4(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
7962       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7963     }
7964     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7965   }
7966   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7967   PetscFunctionReturn(0);
7968 }
7969 
7970 #undef __FUNCT__
7971 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7972 /* Set the constrained indices on each point and separate by fields */
7973 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7974 {
7975   PetscInt      *indices;
7976   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7977   PetscErrorCode ierr;
7978 
7979   PetscFunctionBegin;
7980   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7981   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7982   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7983   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7984   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7985   for (p = pStart; p < pEnd; ++p) {
7986     PetscInt cdof, d;
7987 
7988     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7989     if (cdof) {
7990       PetscInt numConst = 0, foff = 0;
7991 
7992       for (f = 0; f < numFields; ++f) {
7993         const PetscInt *fcind;
7994         PetscInt        fdof, fcdof;
7995 
7996         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7997         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7998         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7999         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8000         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8001         foff     += fdof;
8002         numConst += fcdof;
8003       }
8004       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8005       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8006     }
8007   }
8008   ierr = PetscFree(indices);CHKERRQ(ierr);
8009   PetscFunctionReturn(0);
8010 }
8011 
8012 #undef __FUNCT__
8013 #define __FUNCT__ "DMPlexCreateSection"
8014 /*@C
8015   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8016 
8017   Not Collective
8018 
8019   Input Parameters:
8020 + dm        - The DMPlex object
8021 . dim       - The spatial dimension of the problem
8022 . numFields - The number of fields in the problem
8023 . numComp   - An array of size numFields that holds the number of components for each field
8024 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8025 . numBC     - The number of boundary conditions
8026 . bcField   - An array of size numBC giving the field number for each boundry condition
8027 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8028 
8029   Output Parameter:
8030 . section - The PetscSection object
8031 
8032   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
8033   nubmer of dof for field 0 on each edge.
8034 
8035   Level: developer
8036 
8037 .keywords: mesh, elements
8038 .seealso: DMPlexCreate(), PetscSectionCreate()
8039 @*/
8040 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8041 {
8042   PetscErrorCode ierr;
8043 
8044   PetscFunctionBegin;
8045   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8046   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8047   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8048   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8049   {
8050     PetscBool view = PETSC_FALSE;
8051 
8052     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8053     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8054   }
8055   PetscFunctionReturn(0);
8056 }
8057 
8058 #undef __FUNCT__
8059 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8060 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8061 {
8062   PetscSection   section;
8063   PetscErrorCode ierr;
8064 
8065   PetscFunctionBegin;
8066   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8067   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8068   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8069   PetscFunctionReturn(0);
8070 }
8071 
8072 #undef __FUNCT__
8073 #define __FUNCT__ "DMPlexGetCoordinateSection"
8074 /*@
8075   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8076 
8077   Not Collective
8078 
8079   Input Parameter:
8080 . dm - The DMPlex object
8081 
8082   Output Parameter:
8083 . section - The PetscSection object
8084 
8085   Level: intermediate
8086 
8087 .keywords: mesh, coordinates
8088 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8089 @*/
8090 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8091 {
8092   DM             cdm;
8093   PetscErrorCode ierr;
8094 
8095   PetscFunctionBegin;
8096   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8097   PetscValidPointer(section, 2);
8098   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8099   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8100   PetscFunctionReturn(0);
8101 }
8102 
8103 #undef __FUNCT__
8104 #define __FUNCT__ "DMPlexSetCoordinateSection"
8105 /*@
8106   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8107 
8108   Not Collective
8109 
8110   Input Parameters:
8111 + dm      - The DMPlex object
8112 - section - The PetscSection object
8113 
8114   Level: intermediate
8115 
8116 .keywords: mesh, coordinates
8117 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8118 @*/
8119 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8120 {
8121   DM             cdm;
8122   PetscErrorCode ierr;
8123 
8124   PetscFunctionBegin;
8125   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8126   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8127   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8128   PetscFunctionReturn(0);
8129 }
8130 
8131 #undef __FUNCT__
8132 #define __FUNCT__ "DMPlexGetConeSection"
8133 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8134 {
8135   DM_Plex *mesh = (DM_Plex*) dm->data;
8136 
8137   PetscFunctionBegin;
8138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8139   if (section) *section = mesh->coneSection;
8140   PetscFunctionReturn(0);
8141 }
8142 
8143 #undef __FUNCT__
8144 #define __FUNCT__ "DMPlexGetCones"
8145 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8146 {
8147   DM_Plex *mesh = (DM_Plex*) dm->data;
8148 
8149   PetscFunctionBegin;
8150   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8151   if (cones) *cones = mesh->cones;
8152   PetscFunctionReturn(0);
8153 }
8154 
8155 #undef __FUNCT__
8156 #define __FUNCT__ "DMPlexGetConeOrientations"
8157 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8158 {
8159   DM_Plex *mesh = (DM_Plex*) dm->data;
8160 
8161   PetscFunctionBegin;
8162   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8163   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8164   PetscFunctionReturn(0);
8165 }
8166 
8167 #undef __FUNCT__
8168 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8169 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8170 {
8171   const PetscInt embedDim = 2;
8172   PetscReal      x        = PetscRealPart(point[0]);
8173   PetscReal      y        = PetscRealPart(point[1]);
8174   PetscReal      v0[2], J[4], invJ[4], detJ;
8175   PetscReal      xi, eta;
8176   PetscErrorCode ierr;
8177 
8178   PetscFunctionBegin;
8179   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8180   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8181   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8182 
8183   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8184   else *cell = -1;
8185   PetscFunctionReturn(0);
8186 }
8187 
8188 #undef __FUNCT__
8189 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8190 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8191 {
8192   PetscSection       coordSection;
8193   Vec                coordsLocal;
8194   const PetscScalar *coords;
8195   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8196   PetscReal          x         = PetscRealPart(point[0]);
8197   PetscReal          y         = PetscRealPart(point[1]);
8198   PetscInt           crossings = 0, f;
8199   PetscErrorCode     ierr;
8200 
8201   PetscFunctionBegin;
8202   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8203   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8204   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8205   for (f = 0; f < 4; ++f) {
8206     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8207     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8208     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8209     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8210     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8211     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8212     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8213     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8214     if ((cond1 || cond2)  && above) ++crossings;
8215   }
8216   if (crossings % 2) *cell = c;
8217   else *cell = -1;
8218   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8219   PetscFunctionReturn(0);
8220 }
8221 
8222 #undef __FUNCT__
8223 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8224 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8225 {
8226   const PetscInt embedDim = 3;
8227   PetscReal      v0[3], J[9], invJ[9], detJ;
8228   PetscReal      x = PetscRealPart(point[0]);
8229   PetscReal      y = PetscRealPart(point[1]);
8230   PetscReal      z = PetscRealPart(point[2]);
8231   PetscReal      xi, eta, zeta;
8232   PetscErrorCode ierr;
8233 
8234   PetscFunctionBegin;
8235   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8236   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8237   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8238   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8239 
8240   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8241   else *cell = -1;
8242   PetscFunctionReturn(0);
8243 }
8244 
8245 #undef __FUNCT__
8246 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8247 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8248 {
8249   PetscSection       coordSection;
8250   Vec                coordsLocal;
8251   const PetscScalar *coords;
8252   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8253                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8254   PetscBool          found = PETSC_TRUE;
8255   PetscInt           f;
8256   PetscErrorCode     ierr;
8257 
8258   PetscFunctionBegin;
8259   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8260   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8261   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8262   for (f = 0; f < 6; ++f) {
8263     /* Check the point is under plane */
8264     /*   Get face normal */
8265     PetscReal v_i[3];
8266     PetscReal v_j[3];
8267     PetscReal normal[3];
8268     PetscReal pp[3];
8269     PetscReal dot;
8270 
8271     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8272     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8273     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8274     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8275     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8276     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8277     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8278     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8279     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8280     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8281     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8282     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8283     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8284 
8285     /* Check that projected point is in face (2D location problem) */
8286     if (dot < 0.0) {
8287       found = PETSC_FALSE;
8288       break;
8289     }
8290   }
8291   if (found) *cell = c;
8292   else *cell = -1;
8293   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8294   PetscFunctionReturn(0);
8295 }
8296 
8297 #undef __FUNCT__
8298 #define __FUNCT__ "DMLocatePoints_Plex"
8299 /*
8300  Need to implement using the guess
8301 */
8302 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8303 {
8304   PetscInt       cell = -1 /*, guess = -1*/;
8305   PetscInt       bs, numPoints, p;
8306   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8307   PetscInt      *cells;
8308   PetscScalar   *a;
8309   PetscErrorCode ierr;
8310 
8311   PetscFunctionBegin;
8312   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8313   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8314   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8315   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8316   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8317   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8318   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8319   if (bs != dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8320   numPoints /= bs;
8321   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8322   for (p = 0; p < numPoints; ++p) {
8323     const PetscScalar *point = &a[p*bs];
8324 
8325     switch (dim) {
8326     case 2:
8327       for (c = cStart; c < cEnd; ++c) {
8328         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8329         switch (coneSize) {
8330         case 3:
8331           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8332           break;
8333         case 4:
8334           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8335           break;
8336         default:
8337           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8338         }
8339         if (cell >= 0) break;
8340       }
8341       break;
8342     case 3:
8343       for (c = cStart; c < cEnd; ++c) {
8344         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8345         switch (coneSize) {
8346         case 4:
8347           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8348           break;
8349         case 8:
8350           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8351           break;
8352         default:
8353           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8354         }
8355         if (cell >= 0) break;
8356       }
8357       break;
8358     default:
8359       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8360     }
8361     cells[p] = cell;
8362   }
8363   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8364   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8365   PetscFunctionReturn(0);
8366 }
8367 
8368 /******************************** FEM Support **********************************/
8369 
8370 #undef __FUNCT__
8371 #define __FUNCT__ "DMPlexVecGetClosure"
8372 /*@C
8373   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8374 
8375   Not collective
8376 
8377   Input Parameters:
8378 + dm - The DM
8379 . section - The section describing the layout in v, or NULL to use the default section
8380 . v - The local vector
8381 - point - The sieve point in the DM
8382 
8383   Output Parameters:
8384 + csize - The number of values in the closure, or NULL
8385 - values - The array of values, which is a borrowed array and should not be freed
8386 
8387   Level: intermediate
8388 
8389 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8390 @*/
8391 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8392 {
8393   PetscScalar   *array, *vArray;
8394   PetscInt      *points = NULL;
8395   PetscInt       offsets[32];
8396   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8397   PetscErrorCode ierr;
8398 
8399   PetscFunctionBegin;
8400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8401   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8402   if (!section) {
8403     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8404   }
8405   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8406   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8407   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8408   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8409   /* Compress out points not in the section */
8410   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8411   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8412     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8413       points[q*2]   = points[p];
8414       points[q*2+1] = points[p+1];
8415       ++q;
8416     }
8417   }
8418   numPoints = q;
8419   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8420     PetscInt dof, fdof;
8421 
8422     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8423     for (f = 0; f < numFields; ++f) {
8424       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8425       offsets[f+1] += fdof;
8426     }
8427     size += dof;
8428   }
8429   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8430   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8431   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8432   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8433   for (p = 0; p < numPoints*2; p += 2) {
8434     PetscInt     o = points[p+1];
8435     PetscInt     dof, off, d;
8436     PetscScalar *varr;
8437 
8438     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8439     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8440     varr = &vArray[off];
8441     if (numFields) {
8442       PetscInt fdof, foff, fcomp, f, c;
8443 
8444       for (f = 0, foff = 0; f < numFields; ++f) {
8445         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8446         if (o >= 0) {
8447           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8448             array[offsets[f]] = varr[foff+d];
8449           }
8450         } else {
8451           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8452           for (d = fdof/fcomp-1; d >= 0; --d) {
8453             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8454               array[offsets[f]] = varr[foff+d*fcomp+c];
8455             }
8456           }
8457         }
8458         foff += fdof;
8459       }
8460     } else {
8461       if (o >= 0) {
8462         for (d = 0; d < dof; ++d, ++offsets[0]) {
8463           array[offsets[0]] = varr[d];
8464         }
8465       } else {
8466         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8467           array[offsets[0]] = varr[d];
8468         }
8469       }
8470     }
8471   }
8472   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8473   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8474   if (csize) *csize = size;
8475   *values = array;
8476   PetscFunctionReturn(0);
8477 }
8478 
8479 #undef __FUNCT__
8480 #define __FUNCT__ "DMPlexVecRestoreClosure"
8481 /*@C
8482   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8483 
8484   Not collective
8485 
8486   Input Parameters:
8487 + dm - The DM
8488 . section - The section describing the layout in v, or NULL to use the default section
8489 . v - The local vector
8490 . point - The sieve point in the DM
8491 . csize - The number of values in the closure, or NULL
8492 - values - The array of values, which is a borrowed array and should not be freed
8493 
8494   Level: intermediate
8495 
8496 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8497 @*/
8498 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8499 {
8500   PetscInt       size = 0;
8501   PetscErrorCode ierr;
8502 
8503   PetscFunctionBegin;
8504   /* Should work without recalculating size */
8505   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8506   PetscFunctionReturn(0);
8507 }
8508 
8509 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8510 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8511 
8512 #undef __FUNCT__
8513 #define __FUNCT__ "updatePoint_private"
8514 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8515 {
8516   PetscInt        cdof;   /* The number of constraints on this point */
8517   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8518   PetscScalar    *a;
8519   PetscInt        off, cind = 0, k;
8520   PetscErrorCode  ierr;
8521 
8522   PetscFunctionBegin;
8523   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8524   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8525   a    = &array[off];
8526   if (!cdof || setBC) {
8527     if (orientation >= 0) {
8528       for (k = 0; k < dof; ++k) {
8529         fuse(&a[k], values[k]);
8530       }
8531     } else {
8532       for (k = 0; k < dof; ++k) {
8533         fuse(&a[k], values[dof-k-1]);
8534       }
8535     }
8536   } else {
8537     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8538     if (orientation >= 0) {
8539       for (k = 0; k < dof; ++k) {
8540         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8541         fuse(&a[k], values[k]);
8542       }
8543     } else {
8544       for (k = 0; k < dof; ++k) {
8545         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8546         fuse(&a[k], values[dof-k-1]);
8547       }
8548     }
8549   }
8550   PetscFunctionReturn(0);
8551 }
8552 
8553 #undef __FUNCT__
8554 #define __FUNCT__ "updatePointFields_private"
8555 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8556 {
8557   PetscScalar   *a;
8558   PetscInt       numFields, off, foff, f;
8559   PetscErrorCode ierr;
8560 
8561   PetscFunctionBegin;
8562   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8563   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8564   a    = &array[off];
8565   for (f = 0, foff = 0; f < numFields; ++f) {
8566     PetscInt        fdof, fcomp, fcdof;
8567     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8568     PetscInt        cind = 0, k, c;
8569 
8570     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8571     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8572     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8573     if (!fcdof || setBC) {
8574       if (orientation >= 0) {
8575         for (k = 0; k < fdof; ++k) {
8576           fuse(&a[foff+k], values[foffs[f]+k]);
8577         }
8578       } else {
8579         for (k = fdof/fcomp-1; k >= 0; --k) {
8580           for (c = 0; c < fcomp; ++c) {
8581             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8582           }
8583         }
8584       }
8585     } else {
8586       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8587       if (orientation >= 0) {
8588         for (k = 0; k < fdof; ++k) {
8589           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8590           fuse(&a[foff+k], values[foffs[f]+k]);
8591         }
8592       } else {
8593         for (k = fdof/fcomp-1; k >= 0; --k) {
8594           for (c = 0; c < fcomp; ++c) {
8595             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8596             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8597           }
8598         }
8599       }
8600     }
8601     foff     += fdof;
8602     foffs[f] += fdof;
8603   }
8604   PetscFunctionReturn(0);
8605 }
8606 
8607 #undef __FUNCT__
8608 #define __FUNCT__ "DMPlexVecSetClosure"
8609 /*@C
8610   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8611 
8612   Not collective
8613 
8614   Input Parameters:
8615 + dm - The DM
8616 . section - The section describing the layout in v, or NULL to use the default sectionw
8617 . v - The local vector
8618 . point - The sieve point in the DM
8619 . values - The array of values, which is a borrowed array and should not be freed
8620 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8621 
8622   Level: intermediate
8623 
8624 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8625 @*/
8626 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8627 {
8628   PetscScalar   *array;
8629   PetscInt      *points = NULL;
8630   PetscInt       offsets[32];
8631   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8632   PetscErrorCode ierr;
8633 
8634   PetscFunctionBegin;
8635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8636   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8637   if (!section) {
8638     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8639   }
8640   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8641   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8642   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8643   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8644   /* Compress out points not in the section */
8645   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8646   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8647     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8648       points[q*2]   = points[p];
8649       points[q*2+1] = points[p+1];
8650       ++q;
8651     }
8652   }
8653   numPoints = q;
8654   for (p = 0; p < numPoints*2; p += 2) {
8655     PetscInt fdof;
8656 
8657     for (f = 0; f < numFields; ++f) {
8658       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8659       offsets[f+1] += fdof;
8660     }
8661   }
8662   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8663   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8664   if (numFields) {
8665     switch (mode) {
8666     case INSERT_VALUES:
8667       for (p = 0; p < numPoints*2; p += 2) {
8668         PetscInt o = points[p+1];
8669         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8670       } break;
8671     case INSERT_ALL_VALUES:
8672       for (p = 0; p < numPoints*2; p += 2) {
8673         PetscInt o = points[p+1];
8674         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8675       } break;
8676     case ADD_VALUES:
8677       for (p = 0; p < numPoints*2; p += 2) {
8678         PetscInt o = points[p+1];
8679         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8680       } break;
8681     case ADD_ALL_VALUES:
8682       for (p = 0; p < numPoints*2; p += 2) {
8683         PetscInt o = points[p+1];
8684         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8685       } break;
8686     default:
8687       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8688     }
8689   } else {
8690     switch (mode) {
8691     case INSERT_VALUES:
8692       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8693         PetscInt o = points[p+1];
8694         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8695         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8696       } break;
8697     case INSERT_ALL_VALUES:
8698       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8699         PetscInt o = points[p+1];
8700         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8701         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8702       } break;
8703     case ADD_VALUES:
8704       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8705         PetscInt o = points[p+1];
8706         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8707         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8708       } break;
8709     case ADD_ALL_VALUES:
8710       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8711         PetscInt o = points[p+1];
8712         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8713         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8714       } break;
8715     default:
8716       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8717     }
8718   }
8719   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8720   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8721   PetscFunctionReturn(0);
8722 }
8723 
8724 #undef __FUNCT__
8725 #define __FUNCT__ "DMPlexPrintMatSetValues"
8726 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8727 {
8728   PetscMPIInt    rank;
8729   PetscInt       i, j;
8730   PetscErrorCode ierr;
8731 
8732   PetscFunctionBegin;
8733   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8734   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8735   for (i = 0; i < numIndices; i++) {
8736     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8737   }
8738   for (i = 0; i < numIndices; i++) {
8739     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8740     for (j = 0; j < numIndices; j++) {
8741 #if defined(PETSC_USE_COMPLEX)
8742       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8743 #else
8744       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8745 #endif
8746     }
8747     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8748   }
8749   PetscFunctionReturn(0);
8750 }
8751 
8752 #undef __FUNCT__
8753 #define __FUNCT__ "indicesPoint_private"
8754 /* . off - The global offset of this point */
8755 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8756 {
8757   PetscInt        dof;    /* The number of unknowns on this point */
8758   PetscInt        cdof;   /* The number of constraints on this point */
8759   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8760   PetscInt        cind = 0, k;
8761   PetscErrorCode  ierr;
8762 
8763   PetscFunctionBegin;
8764   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8765   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8766   if (!cdof || setBC) {
8767     if (orientation >= 0) {
8768       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8769     } else {
8770       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8771     }
8772   } else {
8773     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8774     if (orientation >= 0) {
8775       for (k = 0; k < dof; ++k) {
8776         if ((cind < cdof) && (k == cdofs[cind])) {
8777           /* Insert check for returning constrained indices */
8778           indices[*loff+k] = -(off+k+1);
8779           ++cind;
8780         } else {
8781           indices[*loff+k] = off+k-cind;
8782         }
8783       }
8784     } else {
8785       for (k = 0; k < dof; ++k) {
8786         if ((cind < cdof) && (k == cdofs[cind])) {
8787           /* Insert check for returning constrained indices */
8788           indices[*loff+dof-k-1] = -(off+k+1);
8789           ++cind;
8790         } else {
8791           indices[*loff+dof-k-1] = off+k-cind;
8792         }
8793       }
8794     }
8795   }
8796   *loff += dof;
8797   PetscFunctionReturn(0);
8798 }
8799 
8800 #undef __FUNCT__
8801 #define __FUNCT__ "indicesPointFields_private"
8802 /* . off - The global offset of this point */
8803 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8804 {
8805   PetscInt       numFields, foff, f;
8806   PetscErrorCode ierr;
8807 
8808   PetscFunctionBegin;
8809   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8810   for (f = 0, foff = 0; f < numFields; ++f) {
8811     PetscInt        fdof, fcomp, cfdof;
8812     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8813     PetscInt        cind = 0, k, c;
8814 
8815     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8816     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8817     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8818     if (!cfdof || setBC) {
8819       if (orientation >= 0) {
8820         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8821       } else {
8822         for (k = fdof/fcomp-1; k >= 0; --k) {
8823           for (c = 0; c < fcomp; ++c) {
8824             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8825           }
8826         }
8827       }
8828     } else {
8829       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8830       if (orientation >= 0) {
8831         for (k = 0; k < fdof; ++k) {
8832           if ((cind < cfdof) && (k == fcdofs[cind])) {
8833             indices[foffs[f]+k] = -(off+foff+k+1);
8834             ++cind;
8835           } else {
8836             indices[foffs[f]+k] = off+foff+k-cind;
8837           }
8838         }
8839       } else {
8840         for (k = fdof/fcomp-1; k >= 0; --k) {
8841           for (c = 0; c < fcomp; ++c) {
8842             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8843               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8844               ++cind;
8845             } else {
8846               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8847             }
8848           }
8849         }
8850       }
8851     }
8852     foff     += fdof - cfdof;
8853     foffs[f] += fdof;
8854   }
8855   PetscFunctionReturn(0);
8856 }
8857 
8858 #undef __FUNCT__
8859 #define __FUNCT__ "DMPlexMatSetClosure"
8860 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8861 {
8862   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8863   PetscInt      *points = NULL;
8864   PetscInt      *indices;
8865   PetscInt       offsets[32];
8866   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8867   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8868   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8869   PetscErrorCode ierr;
8870 
8871   PetscFunctionBegin;
8872   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8873   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8874   if (useDefault) {
8875     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8876   }
8877   if (useGlobalDefault) {
8878     if (useDefault) {
8879       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8880     } else {
8881       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8882     }
8883   }
8884   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8885   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8886   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8887   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8888   /* Compress out points not in the section */
8889   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8890   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8891     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8892       points[q*2]   = points[p];
8893       points[q*2+1] = points[p+1];
8894       ++q;
8895     }
8896   }
8897   numPoints = q;
8898   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8899     PetscInt fdof;
8900 
8901     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8902     for (f = 0; f < numFields; ++f) {
8903       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8904       offsets[f+1] += fdof;
8905     }
8906     numIndices += dof;
8907   }
8908   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8909 
8910   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8911   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8912   if (numFields) {
8913     for (p = 0; p < numPoints*2; p += 2) {
8914       PetscInt o = points[p+1];
8915       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8916       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8917     }
8918   } else {
8919     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8920       PetscInt o = points[p+1];
8921       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8922       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8923     }
8924   }
8925   if (useGlobalDefault && !useDefault) {
8926     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8927   }
8928   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8929   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8930   if (ierr) {
8931     PetscMPIInt    rank;
8932     PetscErrorCode ierr2;
8933 
8934     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8935     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8936     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8937     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8938     CHKERRQ(ierr);
8939   }
8940   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8941   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8942   PetscFunctionReturn(0);
8943 }
8944 
8945 #undef __FUNCT__
8946 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8947 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8948 {
8949   PetscSection       coordSection;
8950   Vec                coordinates;
8951   const PetscScalar *coords;
8952   const PetscInt     dim = 2;
8953   PetscInt           d, f;
8954   PetscErrorCode     ierr;
8955 
8956   PetscFunctionBegin;
8957   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8958   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8959   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8960   if (v0) {
8961     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8962   }
8963   if (J) {
8964     for (d = 0; d < dim; d++) {
8965       for (f = 0; f < dim; f++) {
8966         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8967       }
8968     }
8969     *detJ = J[0]*J[3] - J[1]*J[2];
8970 #if 0
8971     if (detJ < 0.0) {
8972       const PetscReal xLength = mesh->periodicity[0];
8973 
8974       if (xLength != 0.0) {
8975         PetscReal v0x = coords[0*dim+0];
8976 
8977         if (v0x == 0.0) v0x = v0[0] = xLength;
8978         for (f = 0; f < dim; f++) {
8979           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8980 
8981           J[0*dim+f] = 0.5*(px - v0x);
8982         }
8983       }
8984       detJ = J[0]*J[3] - J[1]*J[2];
8985     }
8986 #endif
8987     PetscLogFlops(8.0 + 3.0);
8988   }
8989   if (invJ) {
8990     const PetscReal invDet = 1.0/(*detJ);
8991 
8992     invJ[0] =  invDet*J[3];
8993     invJ[1] = -invDet*J[1];
8994     invJ[2] = -invDet*J[2];
8995     invJ[3] =  invDet*J[0];
8996     PetscLogFlops(5.0);
8997   }
8998   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
8999   PetscFunctionReturn(0);
9000 }
9001 
9002 #undef __FUNCT__
9003 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9004 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9005 {
9006   PetscSection       coordSection;
9007   Vec                coordinates;
9008   const PetscScalar *coords;
9009   const PetscInt     dim = 2;
9010   PetscInt           d, f;
9011   PetscErrorCode     ierr;
9012 
9013   PetscFunctionBegin;
9014   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9015   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9016   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9017   if (v0) {
9018     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9019   }
9020   if (J) {
9021     for (d = 0; d < dim; d++) {
9022       for (f = 0; f < dim; f++) {
9023         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9024       }
9025     }
9026     *detJ = J[0]*J[3] - J[1]*J[2];
9027     PetscLogFlops(8.0 + 3.0);
9028   }
9029   if (invJ) {
9030     const PetscReal invDet = 1.0/(*detJ);
9031 
9032     invJ[0] =  invDet*J[3];
9033     invJ[1] = -invDet*J[1];
9034     invJ[2] = -invDet*J[2];
9035     invJ[3] =  invDet*J[0];
9036     PetscLogFlops(5.0);
9037   }
9038   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9039   PetscFunctionReturn(0);
9040 }
9041 
9042 #undef __FUNCT__
9043 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9044 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9045 {
9046   PetscSection       coordSection;
9047   Vec                coordinates;
9048   const PetscScalar *coords;
9049   const PetscInt     dim = 3;
9050   PetscInt           d, f;
9051   PetscErrorCode     ierr;
9052 
9053   PetscFunctionBegin;
9054   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9055   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9056   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9057   if (v0) {
9058     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9059   }
9060   if (J) {
9061     for (d = 0; d < dim; d++) {
9062       for (f = 0; f < dim; f++) {
9063         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9064       }
9065     }
9066     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9067     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9068              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9069              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9070     PetscLogFlops(18.0 + 12.0);
9071   }
9072   if (invJ) {
9073     const PetscReal invDet = 1.0/(*detJ);
9074 
9075     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9076     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9077     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9078     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9079     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9080     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9081     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9082     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9083     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9084     PetscLogFlops(37.0);
9085   }
9086   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9087   PetscFunctionReturn(0);
9088 }
9089 
9090 #undef __FUNCT__
9091 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9092 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9093 {
9094   PetscSection       coordSection;
9095   Vec                coordinates;
9096   const PetscScalar *coords;
9097   const PetscInt     dim = 3;
9098   PetscInt           d;
9099   PetscErrorCode     ierr;
9100 
9101   PetscFunctionBegin;
9102   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9103   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9104   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9105   if (v0) {
9106     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9107   }
9108   if (J) {
9109     for (d = 0; d < dim; d++) {
9110       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9111       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9112       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9113     }
9114     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9115              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9116              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9117     PetscLogFlops(18.0 + 12.0);
9118   }
9119   if (invJ) {
9120     const PetscReal invDet = -1.0/(*detJ);
9121 
9122     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9123     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9124     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9125     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9126     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9127     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9128     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9129     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9130     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9131     PetscLogFlops(37.0);
9132   }
9133   *detJ *= 8.0;
9134   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9135   PetscFunctionReturn(0);
9136 }
9137 
9138 #undef __FUNCT__
9139 #define __FUNCT__ "DMPlexComputeCellGeometry"
9140 /*@C
9141   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9142 
9143   Collective on DM
9144 
9145   Input Arguments:
9146 + dm   - the DM
9147 - cell - the cell
9148 
9149   Output Arguments:
9150 + v0   - the translation part of this affine transform
9151 . J    - the Jacobian of the transform to the reference element
9152 . invJ - the inverse of the Jacobian
9153 - detJ - the Jacobian determinant
9154 
9155   Level: advanced
9156 
9157 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9158 @*/
9159 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9160 {
9161   PetscInt       dim, coneSize;
9162   PetscErrorCode ierr;
9163 
9164   PetscFunctionBegin;
9165   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9166   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9167   switch (dim) {
9168   case 2:
9169     switch (coneSize) {
9170     case 3:
9171       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9172       break;
9173     case 4:
9174       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9175       break;
9176     default:
9177       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9178     }
9179     break;
9180   case 3:
9181     switch (coneSize) {
9182     case 4:
9183       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9184       break;
9185     case 8:
9186       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9187       break;
9188     default:
9189       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9190     }
9191     break;
9192   default:
9193     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9194   }
9195   PetscFunctionReturn(0);
9196 }
9197 
9198 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9199 {
9200   switch (i) {
9201   case 0:
9202     switch (j) {
9203     case 0: return 0;
9204     case 1:
9205       switch (k) {
9206       case 0: return 0;
9207       case 1: return 0;
9208       case 2: return 1;
9209       }
9210     case 2:
9211       switch (k) {
9212       case 0: return 0;
9213       case 1: return -1;
9214       case 2: return 0;
9215       }
9216     }
9217   case 1:
9218     switch (j) {
9219     case 0:
9220       switch (k) {
9221       case 0: return 0;
9222       case 1: return 0;
9223       case 2: return -1;
9224       }
9225     case 1: return 0;
9226     case 2:
9227       switch (k) {
9228       case 0: return 1;
9229       case 1: return 0;
9230       case 2: return 0;
9231       }
9232     }
9233   case 2:
9234     switch (j) {
9235     case 0:
9236       switch (k) {
9237       case 0: return 0;
9238       case 1: return 1;
9239       case 2: return 0;
9240       }
9241     case 1:
9242       switch (k) {
9243       case 0: return -1;
9244       case 1: return 0;
9245       case 2: return 0;
9246       }
9247     case 2: return 0;
9248     }
9249   }
9250   return 0;
9251 }
9252 
9253 #undef __FUNCT__
9254 #define __FUNCT__ "DMPlexCreateRigidBody"
9255 /*@C
9256   DMPlexCreateRigidBody - create rigid body modes from coordinates
9257 
9258   Collective on DM
9259 
9260   Input Arguments:
9261 + dm - the DM
9262 . section - the local section associated with the rigid field, or NULL for the default section
9263 - globalSection - the global section associated with the rigid field, or NULL for the default section
9264 
9265   Output Argument:
9266 . sp - the null space
9267 
9268   Note: This is necessary to take account of Dirichlet conditions on the displacements
9269 
9270   Level: advanced
9271 
9272 .seealso: MatNullSpaceCreate()
9273 @*/
9274 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9275 {
9276   MPI_Comm       comm = ((PetscObject) dm)->comm;
9277   Vec            coordinates, localMode, mode[6];
9278   PetscSection   coordSection;
9279   PetscScalar   *coords;
9280   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9281   PetscErrorCode ierr;
9282 
9283   PetscFunctionBegin;
9284   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9285   if (dim == 1) {
9286     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
9287     PetscFunctionReturn(0);
9288   }
9289   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9290   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9291   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9292   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9293   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9294   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9295   m    = (dim*(dim+1))/2;
9296   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9297   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9298   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9299   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9300   /* Assume P1 */
9301   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9302   for (d = 0; d < dim; ++d) {
9303     PetscScalar values[3] = {0.0, 0.0, 0.0};
9304 
9305     values[d] = 1.0;
9306     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9307     for (v = vStart; v < vEnd; ++v) {
9308       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9309     }
9310     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9311     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9312   }
9313   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9314   for (d = dim; d < dim*(dim+1)/2; ++d) {
9315     PetscInt i, j, k = dim > 2 ? d - dim : d;
9316 
9317     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9318     for (v = vStart; v < vEnd; ++v) {
9319       PetscScalar values[3] = {0.0, 0.0, 0.0};
9320       PetscInt    off;
9321 
9322       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9323       for (i = 0; i < dim; ++i) {
9324         for (j = 0; j < dim; ++j) {
9325           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9326         }
9327       }
9328       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9329     }
9330     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9331     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9332   }
9333   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9334   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9335   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9336   /* Orthonormalize system */
9337   for (i = dim; i < m; ++i) {
9338     PetscScalar dots[6];
9339 
9340     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9341     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9342     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9343     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9344   }
9345   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9346   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9347   PetscFunctionReturn(0);
9348 }
9349 
9350 #undef __FUNCT__
9351 #define __FUNCT__ "DMPlexGetHybridBounds"
9352 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9353 {
9354   DM_Plex       *mesh = (DM_Plex*) dm->data;
9355   PetscInt       dim;
9356   PetscErrorCode ierr;
9357 
9358   PetscFunctionBegin;
9359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9360   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9361   if (cMax) *cMax = mesh->hybridPointMax[dim];
9362   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9363   if (eMax) *eMax = mesh->hybridPointMax[1];
9364   if (vMax) *vMax = mesh->hybridPointMax[0];
9365   PetscFunctionReturn(0);
9366 }
9367 
9368 #undef __FUNCT__
9369 #define __FUNCT__ "DMPlexSetHybridBounds"
9370 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9371 {
9372   DM_Plex       *mesh = (DM_Plex*) dm->data;
9373   PetscInt       dim;
9374   PetscErrorCode ierr;
9375 
9376   PetscFunctionBegin;
9377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9378   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9379   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9380   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9381   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9382   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9383   PetscFunctionReturn(0);
9384 }
9385 
9386 #undef __FUNCT__
9387 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9388 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9389 {
9390   DM_Plex *mesh = (DM_Plex*) dm->data;
9391 
9392   PetscFunctionBegin;
9393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9394   PetscValidPointer(cellHeight, 2);
9395   *cellHeight = mesh->vtkCellHeight;
9396   PetscFunctionReturn(0);
9397 }
9398 
9399 #undef __FUNCT__
9400 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9401 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9402 {
9403   DM_Plex *mesh = (DM_Plex*) dm->data;
9404 
9405   PetscFunctionBegin;
9406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9407   mesh->vtkCellHeight = cellHeight;
9408   PetscFunctionReturn(0);
9409 }
9410 
9411 #undef __FUNCT__
9412 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9413 /* We can easily have a form that takes an IS instead */
9414 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9415 {
9416   PetscSection   section, globalSection;
9417   PetscInt      *numbers, p;
9418   PetscErrorCode ierr;
9419 
9420   PetscFunctionBegin;
9421   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9422   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9423   for (p = pStart; p < pEnd; ++p) {
9424     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9425   }
9426   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9427   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9428   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9429   for (p = pStart; p < pEnd; ++p) {
9430     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9431   }
9432   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9433   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9434   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9435   PetscFunctionReturn(0);
9436 }
9437 
9438 #undef __FUNCT__
9439 #define __FUNCT__ "DMPlexGetCellNumbering"
9440 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9441 {
9442   DM_Plex       *mesh = (DM_Plex*) dm->data;
9443   PetscInt       cellHeight, cStart, cEnd, cMax;
9444   PetscErrorCode ierr;
9445 
9446   PetscFunctionBegin;
9447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9448   if (!mesh->globalCellNumbers) {
9449     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9450     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9451     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9452     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9453     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9454   }
9455   *globalCellNumbers = mesh->globalCellNumbers;
9456   PetscFunctionReturn(0);
9457 }
9458 
9459 #undef __FUNCT__
9460 #define __FUNCT__ "DMPlexGetVertexNumbering"
9461 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9462 {
9463   DM_Plex       *mesh = (DM_Plex*) dm->data;
9464   PetscInt       vStart, vEnd, vMax;
9465   PetscErrorCode ierr;
9466 
9467   PetscFunctionBegin;
9468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9469   if (!mesh->globalVertexNumbers) {
9470     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9471     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9472     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9473     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9474   }
9475   *globalVertexNumbers = mesh->globalVertexNumbers;
9476   PetscFunctionReturn(0);
9477 }
9478 
9479 #undef __FUNCT__
9480 #define __FUNCT__ "DMPlexGetScale"
9481 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9482 {
9483   DM_Plex *mesh = (DM_Plex*) dm->data;
9484 
9485   PetscFunctionBegin;
9486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9487   PetscValidPointer(scale, 3);
9488   *scale = mesh->scale[unit];
9489   PetscFunctionReturn(0);
9490 }
9491 
9492 #undef __FUNCT__
9493 #define __FUNCT__ "DMPlexSetScale"
9494 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9495 {
9496   DM_Plex *mesh = (DM_Plex*) dm->data;
9497 
9498   PetscFunctionBegin;
9499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9500   mesh->scale[unit] = scale;
9501   PetscFunctionReturn(0);
9502 }
9503 
9504 
9505 /*******************************************************************************
9506 This should be in a separate Discretization object, but I am not sure how to lay
9507 it out yet, so I am stuffing things here while I experiment.
9508 *******************************************************************************/
9509 #undef __FUNCT__
9510 #define __FUNCT__ "DMPlexSetFEMIntegration"
9511 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9512                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9513                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9514                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9515                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9516                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9517                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9518                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9519                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9520                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9521                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9522                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9523                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9524                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9525                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9526                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9527                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9528 {
9529   DM_Plex *mesh = (DM_Plex*) dm->data;
9530 
9531   PetscFunctionBegin;
9532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9533   mesh->integrateResidualFEM       = integrateResidualFEM;
9534   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9535   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9536   PetscFunctionReturn(0);
9537 }
9538 
9539 #undef __FUNCT__
9540 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9541 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9542 {
9543   Vec            coordinates;
9544   PetscSection   section, cSection;
9545   PetscInt       dim, vStart, vEnd, v, c, d;
9546   PetscScalar   *values, *cArray;
9547   PetscReal     *coords;
9548   PetscErrorCode ierr;
9549 
9550   PetscFunctionBegin;
9551   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9552   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9553   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9554   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9555   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9556   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9557   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9558   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9559   for (v = vStart; v < vEnd; ++v) {
9560     PetscInt dof, off;
9561 
9562     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9563     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9564     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9565     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9566     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9567     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9568   }
9569   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9570   /* Temporary, must be replaced by a projection on the finite element basis */
9571   {
9572     PetscInt eStart = 0, eEnd = 0, e, depth;
9573 
9574     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9575     --depth;
9576     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9577     for (e = eStart; e < eEnd; ++e) {
9578       const PetscInt *cone = NULL;
9579       PetscInt        coneSize, d;
9580       PetscScalar    *coordsA, *coordsB;
9581 
9582       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9583       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9584       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9585       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9586       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9587       for (d = 0; d < dim; ++d) {
9588         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9589       }
9590       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9591       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9592     }
9593   }
9594 
9595   ierr = PetscFree(coords);CHKERRQ(ierr);
9596   ierr = PetscFree(values);CHKERRQ(ierr);
9597 #if 0
9598   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9599   PetscReal      detJ;
9600 
9601   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9602   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9603   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9604 
9605   for (PetscInt c = cStart; c < cEnd; ++c) {
9606     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9607     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9608     const int                          oSize   = pV.getSize();
9609     int                                v       = 0;
9610 
9611     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9612     for (PetscInt cl = 0; cl < oSize; ++cl) {
9613       const PetscInt fDim;
9614 
9615       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9616       if (pointDim) {
9617         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9618           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9619         }
9620       }
9621     }
9622     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9623     pV.clear();
9624   }
9625   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9626   ierr = PetscFree(values);CHKERRQ(ierr);
9627 #endif
9628   PetscFunctionReturn(0);
9629 }
9630 
9631 #undef __FUNCT__
9632 #define __FUNCT__ "DMPlexProjectFunction"
9633 /*@C
9634   DMPlexProjectFunction - This projects the given function into the function space provided.
9635 
9636   Input Parameters:
9637 + dm      - The DM
9638 . numComp - The number of components (functions)
9639 . funcs   - The coordinate functions to evaluate
9640 - mode    - The insertion mode for values
9641 
9642   Output Parameter:
9643 . X - vector
9644 
9645   Level: developer
9646 
9647   Note:
9648   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9649   We will eventually fix it.
9650 
9651 ,seealso: DMPlexComputeL2Diff()
9652 */
9653 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9654 {
9655   Vec            localX;
9656   PetscErrorCode ierr;
9657 
9658   PetscFunctionBegin;
9659   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9660   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9661   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9662   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9663   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9664   PetscFunctionReturn(0);
9665 }
9666 
9667 #undef __FUNCT__
9668 #define __FUNCT__ "DMPlexComputeL2Diff"
9669 /*@C
9670   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9671 
9672   Input Parameters:
9673 + dm    - The DM
9674 . quad  - The PetscQuadrature object for each field
9675 . funcs - The functions to evaluate for each field component
9676 - X     - The coefficient vector u_h
9677 
9678   Output Parameter:
9679 . diff - The diff ||u - u_h||_2
9680 
9681   Level: developer
9682 
9683 .seealso: DMPlexProjectFunction()
9684 */
9685 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9686 {
9687   const PetscInt debug = 0;
9688   PetscSection   section;
9689   Vec            localX;
9690   PetscReal     *coords, *v0, *J, *invJ, detJ;
9691   PetscReal      localDiff = 0.0;
9692   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9693   PetscErrorCode ierr;
9694 
9695   PetscFunctionBegin;
9696   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9697   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9698   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9699   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9700   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9701   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9702   for (field = 0; field < numFields; ++field) {
9703     numComponents += quad[field].numComponents;
9704   }
9705   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9706   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9707   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9708   for (c = cStart; c < cEnd; ++c) {
9709     const PetscScalar *x;
9710     PetscReal          elemDiff = 0.0;
9711 
9712     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9713     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9714     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9715 
9716     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9717       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9718       const PetscReal *quadPoints    = quad[field].quadPoints;
9719       const PetscReal *quadWeights   = quad[field].quadWeights;
9720       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9721       const PetscInt   numBasisComps = quad[field].numComponents;
9722       const PetscReal *basis         = quad[field].basis;
9723       PetscInt         q, d, e, fc, f;
9724 
9725       if (debug) {
9726         char title[1024];
9727         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9728         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9729       }
9730       for (q = 0; q < numQuadPoints; ++q) {
9731         for (d = 0; d < dim; d++) {
9732           coords[d] = v0[d];
9733           for (e = 0; e < dim; e++) {
9734             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9735           }
9736         }
9737         for (fc = 0; fc < numBasisComps; ++fc) {
9738           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9739           PetscReal       interpolant = 0.0;
9740           for (f = 0; f < numBasisFuncs; ++f) {
9741             const PetscInt fidx = f*numBasisComps+fc;
9742             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9743           }
9744           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9745           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9746         }
9747       }
9748       comp        += numBasisComps;
9749       fieldOffset += numBasisFuncs*numBasisComps;
9750     }
9751     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9752     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9753     localDiff += elemDiff;
9754   }
9755   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9756   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9757   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9758   *diff = PetscSqrtReal(*diff);
9759   PetscFunctionReturn(0);
9760 }
9761 
9762 #undef __FUNCT__
9763 #define __FUNCT__ "DMPlexComputeResidualFEM"
9764 /*@
9765   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9766 
9767   Input Parameters:
9768 + dm - The mesh
9769 . X  - Local input vector
9770 - user - The user context
9771 
9772   Output Parameter:
9773 . F  - Local output vector
9774 
9775   Note:
9776   The second member of the user context must be an FEMContext.
9777 
9778   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9779   like a GPU, or vectorize on a multicore machine.
9780 
9781 .seealso: DMPlexComputeJacobianActionFEM()
9782 */
9783 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9784 {
9785   DM_Plex         *mesh = (DM_Plex*) dm->data;
9786   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9787   PetscQuadrature *quad = fem->quad;
9788   PetscSection     section;
9789   PetscReal       *v0, *J, *invJ, *detJ;
9790   PetscScalar     *elemVec, *u;
9791   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9792   PetscInt         cellDof = 0, numComponents = 0;
9793   PetscErrorCode   ierr;
9794 
9795   PetscFunctionBegin;
9796   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9797   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9798   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9799   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9800   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9801   numCells = cEnd - cStart;
9802   for (field = 0; field < numFields; ++field) {
9803     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9804     numComponents += quad[field].numComponents;
9805   }
9806   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9807   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9808   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);
9809   for (c = cStart; c < cEnd; ++c) {
9810     const PetscScalar *x;
9811     PetscInt           i;
9812 
9813     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9814     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9815     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9816 
9817     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9818     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9819   }
9820   for (field = 0; field < numFields; ++field) {
9821     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9822     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9823     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9824     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9825     /* Conforming batches */
9826     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9827     PetscInt numBlocks  = 1;
9828     PetscInt batchSize  = numBlocks * blockSize;
9829     PetscInt numBatches = numBatchesTmp;
9830     PetscInt numChunks  = numCells / (numBatches*batchSize);
9831     /* Remainder */
9832     PetscInt numRemainder = numCells % (numBatches * batchSize);
9833     PetscInt offset       = numCells - numRemainder;
9834 
9835     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9836     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9837                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9838   }
9839   for (c = cStart; c < cEnd; ++c) {
9840     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9841     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9842   }
9843   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9844   if (mesh->printFEM) {
9845     PetscMPIInt rank, numProcs;
9846     PetscInt    p;
9847 
9848     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9849     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9850     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9851     for (p = 0; p < numProcs; ++p) {
9852       if (p == rank) {
9853         Vec f;
9854 
9855         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9856         ierr = VecCopy(F, f);CHKERRQ(ierr);
9857         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9858         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9859         ierr = VecDestroy(&f);CHKERRQ(ierr);
9860         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9861       }
9862       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9863     }
9864   }
9865   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9866   PetscFunctionReturn(0);
9867 }
9868 
9869 #undef __FUNCT__
9870 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9871 /*@C
9872   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9873 
9874   Input Parameters:
9875 + dm - The mesh
9876 . J  - The Jacobian shell matrix
9877 . X  - Local input vector
9878 - user - The user context
9879 
9880   Output Parameter:
9881 . F  - Local output vector
9882 
9883   Note:
9884   The second member of the user context must be an FEMContext.
9885 
9886   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9887   like a GPU, or vectorize on a multicore machine.
9888 
9889 .seealso: DMPlexComputeResidualFEM()
9890 */
9891 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9892 {
9893   DM_Plex         *mesh = (DM_Plex*) dm->data;
9894   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9895   PetscQuadrature *quad = fem->quad;
9896   PetscSection     section;
9897   JacActionCtx    *jctx;
9898   PetscReal       *v0, *J, *invJ, *detJ;
9899   PetscScalar     *elemVec, *u, *a;
9900   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9901   PetscInt         cellDof = 0;
9902   PetscErrorCode   ierr;
9903 
9904   PetscFunctionBegin;
9905   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9906   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9907   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9908   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9909   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9910   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9911   numCells = cEnd - cStart;
9912   for (field = 0; field < numFields; ++field) {
9913     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9914   }
9915   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9916   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);
9917   for (c = cStart; c < cEnd; ++c) {
9918     const PetscScalar *x;
9919     PetscInt           i;
9920 
9921     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9922     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9923     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9924     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9925     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9926     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9927     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9928     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9929   }
9930   for (field = 0; field < numFields; ++field) {
9931     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9932     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9933     /* Conforming batches */
9934     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9935     PetscInt numBlocks  = 1;
9936     PetscInt batchSize  = numBlocks * blockSize;
9937     PetscInt numBatches = numBatchesTmp;
9938     PetscInt numChunks  = numCells / (numBatches*batchSize);
9939     /* Remainder */
9940     PetscInt numRemainder = numCells % (numBatches * batchSize);
9941     PetscInt offset       = numCells - numRemainder;
9942 
9943     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);
9944     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],
9945                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9946   }
9947   for (c = cStart; c < cEnd; ++c) {
9948     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9949     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9950   }
9951   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9952   if (mesh->printFEM) {
9953     PetscMPIInt rank, numProcs;
9954     PetscInt    p;
9955 
9956     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9957     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9958     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9959     for (p = 0; p < numProcs; ++p) {
9960       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9961       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9962     }
9963   }
9964   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9965   PetscFunctionReturn(0);
9966 }
9967 
9968 #undef __FUNCT__
9969 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9970 /*@
9971   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9972 
9973   Input Parameters:
9974 + dm - The mesh
9975 . X  - Local input vector
9976 - user - The user context
9977 
9978   Output Parameter:
9979 . Jac  - Jacobian matrix
9980 
9981   Note:
9982   The second member of the user context must be an FEMContext.
9983 
9984   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9985   like a GPU, or vectorize on a multicore machine.
9986 
9987 .seealso: FormFunctionLocal()
9988 */
9989 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9990 {
9991   DM_Plex         *mesh = (DM_Plex*) dm->data;
9992   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9993   PetscQuadrature *quad = fem->quad;
9994   PetscSection     section;
9995   PetscReal       *v0, *J, *invJ, *detJ;
9996   PetscScalar     *elemMat, *u;
9997   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9998   PetscInt         cellDof = 0, numComponents = 0;
9999   PetscBool        isShell;
10000   PetscErrorCode   ierr;
10001 
10002   PetscFunctionBegin;
10003   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10004   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10005   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10006   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10007   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10008   numCells = cEnd - cStart;
10009   for (field = 0; field < numFields; ++field) {
10010     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10011     numComponents += quad[field].numComponents;
10012   }
10013   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10014   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10015   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);
10016   for (c = cStart; c < cEnd; ++c) {
10017     const PetscScalar *x;
10018     PetscInt           i;
10019 
10020     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10021     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10022     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10023 
10024     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10025     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10026   }
10027   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10028   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10029     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10030     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10031     PetscInt       fieldJ;
10032 
10033     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10034       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10035       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10036       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10037       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10038       /* Conforming batches */
10039       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10040       PetscInt numBlocks  = 1;
10041       PetscInt batchSize  = numBlocks * blockSize;
10042       PetscInt numBatches = numBatchesTmp;
10043       PetscInt numChunks  = numCells / (numBatches*batchSize);
10044       /* Remainder */
10045       PetscInt numRemainder = numCells % (numBatches * batchSize);
10046       PetscInt offset       = numCells - numRemainder;
10047 
10048       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10049       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10050                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10051     }
10052   }
10053   for (c = cStart; c < cEnd; ++c) {
10054     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10055     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10056   }
10057   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10058 
10059   /* Assemble matrix, using the 2-step process:
10060        MatAssemblyBegin(), MatAssemblyEnd(). */
10061   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10062   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10063 
10064   if (mesh->printFEM) {
10065     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10066     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10067     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10068   }
10069   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10070   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10071   if (isShell) {
10072     JacActionCtx *jctx;
10073 
10074     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10075     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10076   }
10077   *str = SAME_NONZERO_PATTERN;
10078   PetscFunctionReturn(0);
10079 }
10080 
10081 
10082 #undef __FUNCT__
10083 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10084 /*@C
10085   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10086   the local section and an SF describing the section point overlap.
10087 
10088   Input Parameters:
10089   + s - The PetscSection for the local field layout
10090   . sf - The SF describing parallel layout of the section points
10091   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10092   . label - The label specifying the points
10093   - labelValue - The label stratum specifying the points
10094 
10095   Output Parameter:
10096   . gsection - The PetscSection for the global field layout
10097 
10098   Note: This gives negative sizes and offsets to points not owned by this process
10099 
10100   Level: developer
10101 
10102 .seealso: PetscSectionCreate()
10103 @*/
10104 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10105 {
10106   PetscInt      *neg;
10107   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10108   PetscErrorCode ierr;
10109 
10110   PetscFunctionBegin;
10111   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10112   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10113   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10114   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10115   /* Mark ghost points with negative dof */
10116   for (p = pStart; p < pEnd; ++p) {
10117     PetscInt value;
10118 
10119     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10120     if (value != labelValue) continue;
10121     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10122     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10123     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10124     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10125     neg[p-pStart] = -(dof+1);
10126   }
10127   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10128   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
10129   if (nroots >= 0) {
10130     if (nroots > pEnd - pStart) {
10131       PetscInt *tmpDof;
10132       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10133       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10134       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10135       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10136       for (p = pStart; p < pEnd; ++p) {
10137         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
10138       }
10139       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10140     } else {
10141       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10142       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10143     }
10144   }
10145   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10146   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10147     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10148 
10149     (*gsection)->atlasOff[p] = off;
10150 
10151     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10152   }
10153   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10154   globalOff -= off;
10155   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10156     (*gsection)->atlasOff[p] += globalOff;
10157 
10158     neg[p] = -((*gsection)->atlasOff[p]+1);
10159   }
10160   /* Put in negative offsets for ghost points */
10161   if (nroots >= 0) {
10162     if (nroots > pEnd - pStart) {
10163       PetscInt *tmpOff;
10164       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10165       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10166       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10167       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10168       for (p = pStart; p < pEnd; ++p) {
10169         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
10170       }
10171       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10172     } else {
10173       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10174       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10175     }
10176   }
10177   ierr = PetscFree(neg);CHKERRQ(ierr);
10178   PetscFunctionReturn(0);
10179 }
10180